Is there a method that works similar to singularize to prepend "a" or "an according to the word?
like f(apple) # => an apple
f(carpet) #=> a carpet
Look here http://deveiate.org/projects/Linguistics/wiki/English and check out this question
If you need something simpler, something that will for instance prepend "an" if a word starts with vowel, you can use my one liner:
String.class_eval { def prepend; %w(a e i o u).include?(downcase.first) ? "an #{self}" : "a #{self}"; end }
Put this in a file prepend.rb in config/initializers folder of your application.
Then you will be able to use
"carrot".prepend => "a carrot"
"apple".prepend => "an apple"
Related
This is actually working (it returns the 5 artists with the most amount of tracks in a database)
def top_five_artists(genre_name)
# TODO: return the 5 artists with the more tracks of genre `genre_name`
Artist.joins(albums: { tracks: :genre }).where(genres: { name: genre_name }).group(:name).order("COUNT(*) DESC").limit(5)
end
but throws the following warning:
DEPRECATION WARNING: Dangerous query method (method whose arguments
are used as raw SQL) called with non-attribute argument(s): "COUNT(*)
DESC". Non-attribute arguments will be disallowed in Rails 6.1. This
method should not be called with user-provided values, such as request
parameters or model attributes. Known-safe values can be passed by
wrapping them in Arel.sql(). (called from top_five_artists at
/home/maxichalbaud/code/maxichalbaud/fullstack-challenges/03-AR-Database/03-ActiveRecord-Basics/Optional-01-Mapping-Existing-Database/app/queries.rb:18)
How would you refactor the "COUNT(*) DESC" line?
You can try this :
def top_five_artists(genre_name)
Artist.joins(albums: { tracks: :genre })
.where(genres: { name: genre_name })
.group(:name)
.order(Arel.sql('count(*) DESC'))
.limit(5)
end
First, you can use order(Arel.sql('count(*) DESC')) to get rid of the warning of deprecation as mu_is_too_short mentioned above, then, you can write your code in multiple lines so that RuboCop won’t bother you with "This line is too long".
I have a unit test that validates that some code throws an exception and that two properties have the expected value. Here is how I do it:
var exception = target.Invoking(t => t.CallSomethingThatThrows())
.ShouldThrow<WebServiceException>()
.And;
exception.StatusCode.Should().Be(400);
exception.ErrorMessage.Should().Be("Bla bla...");
I don't like the look of the assertion that must be done in three statements. Is there an elegant way to do it in a single statement? My first intuition was to use something like this:
target.Invoking(t => t.CallSomethingThatThrows())
.ShouldThrow<WebServiceException>()
.And.StatusCode.Should().Be(400)
.And.ErrorMessage.Should().Be("Bla bla...");
Unfortunately, this doesn't compile.
As said here:
target.Invoking(t => t.CallSomethingThatThrows())
.ShouldThrow<WebServiceException>()
.Where(e => e.StatusCode == 400)
.Where(e => e.ErrorMessage == "Bla bla...");
Not really a direct answer but I note that, if you only have one property of the exception to check, you can use a more fluid syntax like this:
target.Invoking(t => t.CallSomethingThatThrows())
.ShouldThrow<WebServiceException>()
.Which.StatusCode.Should().Be(400);
I have course and category models in my project. Course has many categories and category has many courses.
In course model, I have a scope :search_by_category that will take in a name of category, and find the course where the course's category name is equal to the name.
scope :search_by_category, -> (name){
joins(:categories).where('categories.name = ?', name) if name.present?
}
The scope works fine if I have a single name. But when I have an array of names, it breaks, because where('categories.name = ?', "Some name", "Some other name", "Some more name") is an invalid SQL syntax.
After I experimented with rails console, I find that I need to use OR.
e.g.
where('categories.name = name[0] OR categories.name = name[1])
How can I rewrite my scope to achieve this, or are there any other ways that I can try?
Try this:
array_with_names = ["Some name", "Some other name", "Some more name"]
where('categories.name in (?)', array_with_names)
If you want use OR operator, make array with names and use * splat operator:
array_with_names = ["Some name", "Some other name", "Some more name"]
where('categories.name = ? OR categories.name = ? OR categories.name = ?', *array_with_names)
But i think this useless.
Use Rails syntax for this. ActiveRecord will automatically detect you are using array and will construct proper SQL syntax for you (whether to use IN or =).
scope :search_by_category, -> (array_with_names){
joins(:categories).where(categories: { name: array_with_names })
}
An example will be the best to describe my question
got this 2 documents
{ a : [] }
{ a [{x:1,y:2},{x:3,y:4}]
so both docs have this a attr
one empty one not
how can i select only a's that their array is not empty?
lets say model name is Model
I tried
Model.not.with_size(a:0)
without success
any direction?
Try this
Model.where(:a.not => {'$size' => 0})
I'm making a rails application so that users can search a database of midi records and find midi files that correspond to the attributes that I've given them.
For example, a user might enter data into an html form for a midi file with name = "blah" composer= "buh" and difficulty = "insane".
This is all fine and well, except that I would like when the user enters no data for a field, that field is ignored when doing the select statement on the database.
Right now this is what my select statement looks like:
#midis=Midi.where(:name => params[:midi][:name],
:style => params[:midi][:style],
:numparts => params[:midi][:numparts],
:composer=> params[:midi][:composer],
:difficulty => params[:midi[:difficulty])
This works as expected, but if for example he/she leaves :composer blank, the composer field should not considered at all. This is probably a simple syntax thing but i wasn't able to find any pages on it.
Thanks very much!
Not sure if Arel supports that directly, but you could always do something like:
conditions = {
:name => params[:midi][:name],
:style => params[:midi][:style],
:numparts => params[:midi][:numparts],
:composer=> params[:midi][:composer],
:difficulty => params[:midi[:difficulty]
}
#midis=Midi.where(conditions.select{|k,v| v.present?})
Try this:
# Select the key/value pairs which are actually set and then convert the array back to Hash
c = Hash[{
:name => params[:midi][:name],
:style => params[:midi][:style],
:numparts => params[:midi][:numparts],
:composer => params[:midi][:composer],
:difficulty => params[:midi][:difficulty]
}.select{|k, v| v.present?}]
Midi.where(c)