rails singularize to a / an - ruby-on-rails-3

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

How would you replace this SQL query in Ruby so that you only use ActiveRecord code?

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".

How to chain multiple 'And' when checking exception with FluentAssertions

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);

How to use OR in Rails 4 ActiveRecord named scope

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 })
}

Mongoid query by referenced collection

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})

Configuring rails database query so that blank string parameters are ignored

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)