Rails-y way to query a model with a belongs_to association

有些话、适合烂在心里 提交于 2019-12-05 06:12:11

问题


I have two models:

class Wine
  belongs_to :region
end

class Region
  has_many :wines
end

I am attempting to use the #where method with a hash built from transforming certain elements from the params hash into a query hash, for example { :region => '2452' }

def index
  ...
  @wines = Wine.where(hash)
  ...
end

But all I get is a column doesn't exist error when the query is executed:

ActiveRecord::StatementInvalid: PGError: ERROR:  column wines.region does not exist
LINE 1: SELECT "wines".* FROM "wines"  WHERE "wines"."region" =...

Of course, the table wines has region_id so if I queried for region_id instead I would not get an error.

The question is the following:

Is there a rails-y way to query the Wine object for specific regions using the id in the #where method? I've listed some options below based on what I know I can do.

Option 1: I could change the way that I build the query hash so that each field has _id (like { :region_id => '1234', :varietal_id => '1515' } but not all of the associations from Wine are belongs_to and thus don't have an entry in wines for _id, making the logic more complicated with joins and what not.

Option 2: Build a SQL where clause, again using some logic to determine whether to use the id or join against another table... again the logic would be somewhat more complicated, and delving in to SQL makes it feel less rails-y. Or I could be wrong on that front.

Option(s) 3..n: Things I haven't thought about... your input goes here :)


回答1:


You could set up a scope in the Wine model to make it more rails-y ...

class Wine < ActiveRecord::Base

  belongs_to :region
  attr_accessible :name, :region_id

  scope :from_region, lambda { |region|
    joins(:region).where(:region_id => region.id)
  }
end

So then you can do something like:

region = Region.find_by_name('France')
wine =   Wine.from_region(region)

Edit 1:

or if you want to be really fancy you could do a scope for multiple regions:

scope :from_regions, lambda { |regions|
  joins(:region).where("region_id in (?)", regions.select(:id))
}

regions = Region.where("name in (?)", ['France','Spain']) # or however you want to select them
wines =   Wine.from_regions(regions) 

Edit 2:

You can also chain scopes and where clauses, if required:

regions = Region.where("name in (?)", ['France','Spain'])
wines =   Wine.from_regions(regions).where(:varietal_id => '1515')



回答2:


Thanks to all who replied. The answers I got would be great for single condition queries but I needed something that could deal with a varying number of conditions.

I ended up implementing my option #1, which was to build a condition hash by iterating through and concatenating _id to the values:

def query_conditions_hash(conditions)
  conditions.inject({}) do |hash, (k,v)| 
    k = (k.to_s + "_id").to_sym
    hash[k] = v.to_i
    hash
  end
end

So that the method would take a hash that was built from params like this:

{ region => '1235', varietal => '1551', product_attribute => '9' }

and drop an _id onto the end of each key and change the value to an integer:

{ region_id => 1235, varietal_id => 1551, product_attribute_id => 9 }

We'll see how sustainable this is, but this is what I went with for now.



来源:https://stackoverflow.com/questions/13619560/rails-y-way-to-query-a-model-with-a-belongs-to-association

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!