Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>After some console experimentation--you can just say <code>employee.department.company</code>, even if department is not yet saved. <code>department_id</code> may be nil, but the <code>department</code> association is there.</p> <pre><code>2.0.0-p195 :041 &gt; c = Company.create (0.4ms) begin transaction SQL (0.9ms) INSERT INTO "companies" DEFAULT VALUES (486.4ms) commit transaction =&gt; #&lt;Company id: 4, department: nil, custom_fields: nil&gt; 2.0.0-p195 :042 &gt; d = c.departments.build =&gt; #&lt;Department id: nil, company_id: 4, employee_id: nil&gt; 2.0.0-p195 :043 &gt; e = d.employees.build =&gt; #&lt;Employee id: nil, department_id: nil&gt; 2.0.0-p195 :044 &gt; e.department === d =&gt; true 2.0.0-p195 :045 &gt; e.department.company === c =&gt; true </code></pre> <p><strong>Edit:</strong> so, this didn't work on a different machine with another clean Rails 4 app. However, it still works on my laptop...also in a clean Rails 4 app. Let's try and figure out what's different! </p> <pre><code>e.method(:department) =&gt; #&lt;Method: Employee(Employee::GeneratedFeatureMethods)#department&gt; e.method(:department).source_location =&gt; ["/home/neil/.rvm/gems/ruby-2.0.0-p195/gems/activerecord- 4.0.0/lib/active_record/associations/builder/association.rb", 69] </code></pre> <p>Which leads us here:</p> <pre><code>def define_readers mixin.class_eval &lt;&lt;-CODE, __FILE__, __LINE__ + 1 def #{name}(*args) association(:#{name}).reader(*args) end CODE end </code></pre> <p>No surprises really, this defines a method called <code>:department</code></p> <pre><code>def department *args association(:department).reader(*args) end </code></pre> <p>That call to <code>reader</code> just returns us the @target of the association if it is present, or tries to read it if it has an id at hand. In my case the <code>@target</code> is set to department <code>d</code>. To discover the point at which @target is set, we can intercept <code>target=</code> in <code>ActiveRecord::Associations::Association</code>:</p> <pre><code>class ActiveRecord::Associations::Association alias :_target= :target= def target= t puts "#{caller} set the target!" _target = t end end </code></pre> <p>Now when we call <code>d.employees.build</code> we get this...</p> <pre><code>"/home/neil/.rvm/gems/ruby-2.0.0-p195/gems/activerecord-4.0.0/lib/active_record/associations/association.rb:112:in `set_inverse_instance'", "/home/neil/.rvm/gems/ruby-2.0.0-p195/gems/activerecord-4.0.0/lib/active_record/associations/collection_association.rb:376:in `add_to_target'", "/home/neil/.rvm/gems/ruby-2.0.0-p195/gems/activerecord-4.0.0/lib/active_record/associations/collection_association.rb:114:in `build'" </code></pre> <p><code>set_inverse_instance</code> is checking <code>invertible_for?(record)</code>, (where <code>record</code> is our new Employee instance.) This just calls <code>reflection.inverse_of</code>, and this has to return a truthy value in order for target to be set.</p> <pre><code>def inverse_of return unless inverse_name @inverse_of ||= klass.reflect_on_association inverse_name end </code></pre> <p>So let's try that out...</p> <pre><code>2.0.0-p195 :055 &gt; Employee.reflect_on_association :department =&gt; #&lt;ActiveRecord::Reflection::AssociationReflection:0xa881788 @macro=:belongs_to, @name=:department, @scope=nil, @options={}, @active_record=Employee(id: integer, department_id: integer), @plural_name="departments", @collection=false, @class_name="Department", @foreign_key="department_id"&gt; </code></pre> <p>That's non-nil, so @target will be set in my association when I call <code>d.employee.build</code>, so I can call <code>e.department</code>, and so on. So why is it non-nil here, but nil for you (and over on my other machine?) If I call <code>Employee.reflections</code>, I get the following:</p> <pre><code>&gt; Employee.reflections =&gt; {:department=&gt;#&lt;ActiveRecord::Reflection::AssociationReflection:0x9a04598 @macro=:belongs_to, @name=:department, @scope=nil, @options={}, @active_record=Employee(id: integer, department_id: integer), @plural_name="departments", @collection=false, @class_name="Department", @foreign_key="department_id"&gt;} </code></pre> <p>This is the product of the <code>belongs_to</code> method--it's got to be there if you look. So why (in your case) doesn't <code>set_inverse_instance</code> find it? </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload