Rails has_many with dynamic conditions

Ruby on-RailsModel

Ruby on-Rails Problem Overview


What I want is to create a Model that connects with another using a has_many association in a dynamic way, without the foreign key like this:

has_many :faixas_aliquotas, :class_name => 'Fiscal::FaixaAliquota',
            :conditions => ["regra_fiscal = ?", ( lambda { return self.regra_fiscal } ) ]

But I get the error:

: SELECT * FROM "fis_faixa_aliquota" WHERE ("fis_faixa_aliquota".situacao_fiscal_id = 1
AND (regra_fiscal = E'--- !ruby/object:Proc {}'))

Is this possible?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

Rails 4+ way (Thanks to Thomas who answered this below):
has_many :faixas_aliquotas, -> (object) { 
           where("regra_fiscal = ?", object.regra_fiscal)
         },
         :class_name => 'Fiscal::FaixaAliquota'
Rails 3.1+ way:
has_many :faixas_aliquotas, :class_name => 'Fiscal::FaixaAliquota',
         :conditions => proc { "regra_fiscal = #{self.regra_fiscal}" }
Rails 3 and below:
has_many :faixas_aliquotas, :class_name => 'Fiscal::FaixaAliquota',
         :conditions => ['regra_fiscal = #{self.regra_fiscal}']

No. This is not a mistake. The conditions are specified in single quotes and still contains the code #{self.regra_fiscal}. When the conditions clause is evaulated, the regra_fiscal method will be called on the object of self (whatever the class is). Putting double quotes will not work.

I hope this is what you are looking for.

Solution 2 - Ruby on-Rails

Rails 4+ way:

has_many :faixas_aliquotas, 
         -> (object){ where("regra_fiscal = ?", object.regra_fiscal)},  
         :class_name => 'Fiscal::FaixaAliquota'

Solution 3 - Ruby on-Rails

There is another kind of solution. However, this wont be the default scope.

has_many :faixas_aliquotas, :class_name => 'Fiscal::FaixaAliquota' do 
  def filter(situacao_fiscal)
    find(:all, :conditions => {:regra_fiscal => situacao_fiscal.regra_fiscal})
  end
end

This way you would be able to do

situacao_fiscal.faixas_aliquotas.filter(situacao_fiscal)

I am not sure if this is elegant and something that would solve your problem. There may be better ways of doing this.

Solution 4 - Ruby on-Rails

Rails 4+ another way:

has_many :faixas_aliquotas, -> (object){ where(regra_fiscal: object.regra_fiscal) }, :class_name => 'Fiscal::FaixaAliquota'

Solution 5 - Ruby on-Rails

In Rails 3.1 need to use proc, Proc.new { "field = #{self.send(:other_field)}" }

Solution 6 - Ruby on-Rails

In Rails 3.1 you can use Proc.new for your conditions. as stated by @Amala, but instead generate a hash like this:

has_many :faixas_aliquotas, :class_name => 'Fiscal::FaixaAliquota',
   :conditions => {:regra_fiscal => Proc.new { {:regra_fiscal => self.regra_fiscal} }

The benefit of this approach is that if you do object.faixas_aliquotas.build, the newly created object will automatically have the same regra_fiscal attribute as the parent.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFabiano SorianiView Question on Stackoverflow
Solution 1 - Ruby on-RailsChirantanView Answer on Stackoverflow
Solution 2 - Ruby on-RailsThomasView Answer on Stackoverflow
Solution 3 - Ruby on-RailsChirantanView Answer on Stackoverflow
Solution 4 - Ruby on-RailsGeoffreyHervetView Answer on Stackoverflow
Solution 5 - Ruby on-RailsAmalaView Answer on Stackoverflow
Solution 6 - Ruby on-RailsbayfieldcoderView Answer on Stackoverflow