Refactor this block of routes? - ruby-on-rails

I have to manually redirect a set of URLs, but seems like there's got to be a more efficient way (in terms of # of lines) than what I've currently go.
match "/articles/care" => redirect("/articles/category/care")
match "/articles/food-diet" => redirect("/articles/category/food-diet")
match "/articles/basics" => redirect("/articles/category/basics")
match "/articles/training" => redirect("/articles/category/training")
match "/articles/recipes" => redirect("/articles/category/recipes")
match "/articles/life" => redirect("/articles/category/life")

Try this out:
for category in %w{ care food-diet training recipes life }
match "/articles/#{category}" => redirect("/articles/category/#{category}")
end

Related

How to perform morphology analysis in RoR?

I am looking for ways to turn single words to their infinitives inside models:
cats -> cat
sharpest -> sharp
etc.
Do you know of any gems or libraries that are able to do that?
String#singularize is providing : The reverse of pluralize, returns the singular form of a word in a string.
'posts'.singularize # => "post"
'octopi'.singularize # => "octopus"
'sheep'.singularize # => "sheep"
'word'.singularize # => "word"
'the blue mailmen'.singularize # => "the blue mailman"
'CamelOctopi'.singularize # => "CamelOctopus"
'leyes'.singularize(:es) # => "ley"
for String#pluralize : Returns the plural form of the word in the string.
'post'.pluralize # => "posts"
'octopus'.pluralize # => "octopi"
'sheep'.pluralize # => "sheep"
'words'.pluralize # => "words"
'the blue mailman'.pluralize # => "the blue mailmen"
'CamelOctopus'.pluralize # => "CamelOctopi"
'apple'.pluralize(1) # => "apple"
'apple'.pluralize(2) # => "apples"
'ley'.pluralize(:es) # => "leyes"
'ley'.pluralize(1, :es) # => "ley"
In addition you can also have a look at 'verbs' gem
Conjugates most common english verbs for all persons, tenses, standard
aspects, and modern moods (with active diathesis). Standard and
exceptional spelling rules are obeyed.

ActiveRecord Include, how to use in nested records?

I currently have the following:
#threads = current_user.threads.includes(:user, :thread_members)
I then take threads and do the following:
#threads.each do |thread|
thread_members = thread.thread_members_active(current_user)
#threadList << {
:id => thread.id,
:uuid => thread.uuid,
:user_id => thread.user.id,
:last_activity_at => thread.last_activity_at,
:user_count => thread_members.length,
:user_photos => thread_members.collect { |thread_member|
{
:id => thread_member.user.id,
:photo => thread_member.user.photo(:thumb),
:name => thread_member.user.full_name
}
},
:caption => thread.caption
}
end
The issue here is that every EACH loop, rails is hitting the DB for the same basic records. Rails sees to be caching as I see CACHE in the log but it's mighty messy. Leaves me wishing I could do some type of includes so there wasn't so many db requests.
Any ideas on how this can be optimized? Something around including all the users in one db hit?
Thanks
If you don't want any DB queries in the loop, you have to define everything that's used there in the named associations that are included, so instead of a thread_members_active method you'd define a thread_members_active association which has the same behavior. Note that the association also needs to use includes on user. Can't give you more right now, but maybe that helps a bit.
Edit: Check out the "Eager loading of associations" part of this doc:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Rails as_json includes with conditions

I have problems to restrict an as_json include by a dynamic attribute:
#pirates_ships = #current_account.pirates.as_json(:include => {:ships => {:only => [:id, :name]}}, :only => [:id, :last_name])
This for sure gives me all pirates with or without their ships.
But I also need to restrict the ships by e.g. ships.ocean_id
I tried resolving it by includes with conditions:
pirates.includes(:ships).where("ships.ocean_id = ?", #ocean.id).as_json(...)
The restriction works, but now all pirates without a ship are lost.
Also no luck with my own JOIN Syntax.
Any ideas?
Ahoy
UPDATE
My solution so far is to manually eager load. This way I can have my dynamic conditions:
#pirates = #current_account.pirates
#ships = #current_account.ships.where({:pirate_id.in => #pirates, :ocean_id => #ocean.id})
render :json => { :pirates => #pirates.as_json(...), :ships => #ships.as_json(...) }
My Ajax callback can now iterate over :pirates and add for each pirate his ships if any.
(I use a JS template engine clientside to generate the view from the JSON response)
Not very elegant, but performance is important in my case.
I'am still open for better ideas.
I tried dynamic has_many :ships, :conditions => ...
but that's a bit fiddly.
I think your best bet would be altering the #pirates_ships hash after generating it from as_json (I tried multiple variations of includes, etc. and couldn't get anything to work).
#pirates_ships = #current_account.pirates.as_json(:include => :ships)
#pirates_ships.each do |pirate|
pirate[:ships].delete_if{ |ship| ship.ocean_id != #ocean.id }
end
# Now, #pirates_ships should contain ALL pirates, as well as ships for #ocean

Need to return all users with genre 'Acoustic'

Is there a better way to write this:
User.where(:genre_id => Genre.where(:name => 'Acoustic').first.id).first.first_name
Basically, I am trying to return all users with genre 'Acoustic'.
Above will work if there are users with the Acoustic setting. But if i do:
User.where(:genre_id => Genre.where(:name => 'Pop').first.id).first.first_name
I will get an error, since there are no users associated with the pop
genre...
Any suggestions to get this to work?
In a general way, many-to-many relationships really suck in mongo (the price you pay for has_one/has_many being so awesome)
I am assuming the problem is that Genre.where(:name => 'Pop').first returns nil? I would do this
User.where(:genre_id => g).first.first_name if g = Genre.where(:name => 'Pop').first.try(:id)
or if massive one line expressions aren't your thing
g = Genre.where(:name => 'Pop').first.try(:id)
if g
User.where(:genre_id => g).first.first_name
end
Doesn't the usual nested where work?
User.where(:genre => { :name => 'Pop' })
You could try with find instead of where for Genre:
User.where(:genre_id => Genre.find(:first, :conditions => { :name => 'Pop' }))
This should work even when Genre.find returns nil.

Checking if ActiveRecord find returns a result

I'm trying to check if a find method returns a result. My find method is the following:
post = Post.find(:all, :conditions => { :url => params['url'] }, :limit => 1)
What would be a good way to check that post contains a result?
find :all returns an empty array ([]) if no rows are returned, so you can just use it this way:
post = Post.find(:all, :conditions => { :url => params['url'] }, :limit => 1)
unless post.empty?
# do something...
end
By the way, if you do find :all you're going to get an array, not a single row. If you're trying to get just one Post, it would be cleaner to use the find_by helper or find :first or just first instead:
post = Post.find_by_url params['url']
# or
post = Post.first :conditions => { :url => params['url'] }
# then...
if post
# do something...
end
You can try ActiveRecord::Base.exists? before
Post.exists?(:conditions => { :url => params['url'] })
Use the BANG! version of the find_by_url method to get it to raise an exception of it could not be found and then rescue it later on in that same method/action.
def show
Post.find_by_url!(params[:url])
rescue ActiveRecord::RecordNotFound
flash[:notice] = "The URL you were looking for could not be found."
redirect_to root_path
end
end
If you didn't raise an exception here I believe that Rails would show the public/404.html page.
if post doesn't contain any result it will be an empty list and then:
post.empty?
will return true.
it may be as simple as changing your finder to:
post = Post.find(:first, :conditions => { :url => params['url'] })
With this finder, post will either return a single value or nil. Because nil behaves like false in a condition statement, you can say something like the following:
if post
# do something
else
# do something else
end
Post.find_by_id(id_column_value)
will return nil rathering than blowing up your program when it can't find a record.
Of course, there's
x = Post.where(:any_column_name => value)
which always returns an array of results. In which case you could just run an
x.each {|t| f(t) }
or
y = x.map {|t| f(t)}
or of course,
x[0], x[1], etc
Sorry I got a little carried away there
Another way to do it is checking with ActiveRecord#any?.

Resources