Question

I'm having a little brain block when it comes to condensing the use of two #find methods in ActiveRecord down to a single statement and SQL query.

I have a Sinatra route where the slug of both a parent and child record are supplied (the parent has many children). Atm I'm first finding the parent with a #find_by_slug call and then the child by #find_by_slug again on the matched parents association.

This results in two SQL queries that in my mind should be able to be condensed down to one easily... Only I can't work out how that's achieved with ActiveRecord.

Model, route and AR log below. Using ActiveRecord 3.2

Edit

I realised I need to clarify the exact outcome to require (I write this very late in the day). I only require the Episode but atm I'm getting the Show first in-order to get to the Episode. I only require the Episode and figured their must be a way to get at that object without adding the extra line and getting the Show first.

Model

class Show < ActiveRecord::Base
  has_many :episodes
end

class Episode < ActiveRecord::Base
  belongs_to :show
end

Sinatra route

get "/:show_slug/:episode_slug" do
  @show = Show.find_by_slug show_slug
  @episode = @show.episodes.find_by_slug episode_slug

  render_template :"show/show"
end

ActiveRecord logs

Show Load (1.0ms)  SELECT `shows`.* FROM `shows` WHERE `shows`.`slug` = 'the-show-slug' LIMIT 1
Episode Load (1.0ms)  SELECT `show_episodes`.* FROM `show_episodes` WHERE `show_episodes`.`show_id` = 1 AND `show_episodes`.`slug` = 'episode-21' LIMIT 1
Was it helpful?

Solution

If you only need the @episode, you can maybe do

@episode = Episode.joins(:shows).where('shows.slug = ?', show_slug).where('episodes.slug = ?', episode_slug).first

If you also need @show, you've got to have two queries.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top