tybro0103
tybro0103

Reputation: 49743

Rails' includes() doesn't work with dynamic association conditions

Working on a multi-tenant app where most of my models will have a tenant_id field so I can ensure read permissions by finding through the association (current_tenant.applications.find(params[:id])):

class Application < ActiveRecord::Base
  belongs_to :tenant
  has_many :app_questions, :conditions => proc {{:tenant_id => tenant_id}}, :dependent => :destroy
end

I like how this allows me to elegantly create a new AppQuestion with the tenant_id set automatically:

@application = current_tenant.applications.find(params[:app_question][:application_id])
@question = @application.app_questions.build(params[:app_question])
#...

Problem is, when I try to use includes() to eager-load the association it throws an error:

current_tenant.applications.where(:id => params[:id]).includes(:app_questions => :app_choices).first

NoMethodError (undefined method `tenant_id' for #<Class:0x007fbffd4a9420>):
  app/models/application.rb:7:in `block in <class:Application>'

I could refactor so that I don't have to have the proc in the association conditions, but am wondering if anyone has a better solution.

The ref does say: "If you need to evaluate conditions dynamically at runtime, use a proc"

Upvotes: 2

Views: 1211

Answers (3)

the8472
the8472

Reputation: 43150

Assuming the relation itself works you could try preload instead of includes

Upvotes: 0

Fabio
Fabio

Reputation: 19216

I've replied to the other question with more details trying to explain why this cannot work.

When they say dynamic is because the proc can be executed at runtime, but not in the context of an existing instance of the Application class because it doesn't exist when you invoke this relation

Application.where(:id => params[:id]).includes(:app_questions => :app_choices)

Upvotes: 2

Michael Slade
Michael Slade

Reputation: 13877

The ability for :conditions to accept a proc isn't documented in the ref. I suspect it doesn't work the way you guessed it might.

:conditions accepts either an SQL WHERE clause, or a hash that can be turned into on. It's inserted into the SQL that gets the :app_questions records, and if it's a proc it's only called once to get the snippet for the SQL statement to be constructed.

It might help to have a look at your database relationships. Should app_questions link to tenants or applications?

Upvotes: 0

Related Questions