{"id":3184,"date":"2012-11-22T14:39:19","date_gmt":"2012-11-22T11:39:19","guid":{"rendered":"http:\/\/railsware.com\/blog\/?p=3184"},"modified":"2021-08-16T15:30:06","modified_gmt":"2021-08-16T12:30:06","slug":"rails-3-2-9-through-associations-issues","status":"publish","type":"post","link":"https:\/\/railsware.com\/blog\/rails-3-2-9-through-associations-issues\/","title":{"rendered":"Rails 3.2.9 through associations issues"},"content":{"rendered":"\n<p>Recent 3.2.9 release bugfix has brought an issue for <code>through<\/code> associations.<br><code>inverse_of<\/code> usage can solve the problem only partially (polymorphic associations are still affected).<\/p>\n\n\n\n<p><span style=\"font-weight: bold;\">UPDATE<\/span>: patch that introduced this issue has just been <a href=\"https:\/\/github.com\/rails\/rails\/pull\/8895\" target=\"_blank\" rel=\"noreferrer noopener\">reverted in rails master<\/a>.<\/p>\n\n\n\n<p>Few days ago Rails 3.2.9 was released.<br>Among the bugfixes a <a href=\"https:\/\/github.com\/rails\/rails\/pull\/7661\" target=\"_blank\" rel=\"noreferrer noopener\">fix for <code>through<\/code> associations<\/a> is present, and since 3.2.9 join model instances are built even though the object is not saved yet.<\/p>\n\n\n\n<p>To get the point take a look at these simple models with <code>User<\/code> and <code>Team<\/code> joined with each other <code>through<\/code> <code>UserMembership<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:ruby\">class User &lt; ActiveRecord::Base\n  has_many :user_memberships\n  has_many :teams, through: :user_memberships\nend\n\nclass Team &lt; ActiveRecord::Base\n  has_many :user_memberships\n  has_many :users, through: :user_memberships\nend\n\nclass UserMembership &lt; ActiveRecord::Base\n  belongs_to :team\n  belongs_to :user\n  validates :team, :user, presence: true\nend\n<\/pre>\n\n\n\n<p>Before Rails 3.2.9 this code does not build any <code>UserMembership<\/code> instances:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:ruby\">team = Team.new(users: [User.first])\nteam.valid?           #=&gt; true\nteam.user_memberships #=&gt; []\n<\/pre>\n\n\n\n<p>But since Rails 3.2.9 <code>UserMembership<\/code> instance is built:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:ruby\">team = Team.new(users: [User.first])\nteam.valid?                      #=&gt; false\nteam.user_memberships            #=&gt; [#]\nteam.user_memberships.first.team #=&gt; nil\n<\/pre>\n\n\n\n<p>Oh, have you noticed that <code>team<\/code> is invalid now? Aahh, now when it get&#8217;s complicated.<\/p>\n\n\n\n<p>Built instance of a join <code>UserMembership<\/code> model<br>has no <code>team<\/code> set and that&#8217;s why it&#8217;s invalid (it has <code>validate :team, :user, presence: true<\/code>).<br>As soon as join model instance is invalid <code>team<\/code> is invalid as well.<\/p>\n\n\n\n<p>To fix this validation issues in this particular case the one should use <code>inverse_of<\/code> for the associations like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:ruby\">class User &lt; ActiveRecord::Base\n  has_many :user_memberships, :inverse_of =&gt; :user\n  has_many :teams, through: :user_memberships\nend\n\nclass Team &lt; ActiveRecord::Base\n  has_many :user_memberships, :inverse_of =&gt; :team\n  has_many :users, through: :user_memberships\nend\n\nteam = Team.new(users: [User.first])\nteam.valid?                        #=&gt; true\nteam.user_memberships.first.valid? #=&gt; true\nteam.user_memberships.first.team   #=&gt; #\n<\/pre>\n\n\n\n<p><code>inverse_of<\/code> takes care of associations objects in-memory synchronization, so now <code>UserMembership<\/code> instance has a <code>team<\/code> and it&#8217;s valid.<br>Unfortunately polymorphic associations are still affected &#8211; follow <a href=\"https:\/\/github.com\/rails\/rails\/issues\/8269\" target=\"_blank\" rel=\"noreferrer noopener\">this github discussion<\/a> for more info.<\/p>\n\n\n\n<p>That said, if you&#8217;ve just upgraded to 3.2.9 and your tests are failing review the associations and fix them whenever it&#8217;s possible by using <code>inverse_of<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recent 3.2.9 release bugfix has brought an issue for through associations.inverse_of usage can solve the problem only partially (polymorphic associations are still affected). UPDATE: patch that introduced this issue has just been reverted in rails master. Few days ago Rails 3.2.9 was released.Among the bugfixes a fix for through associations is present, and since 3.2.9&#8230;<\/p>\n","protected":false},"author":34,"featured_media":3196,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[],"coauthors":["Innokenty Mihailov"],"class_list":["post-3184","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"aioseo_notices":[],"categories_data":[{"name":"Engineering","link":"https:\/\/railsware.com\/blog?category=development"}],"post_thumbnails":"https:\/\/railsware.com\/blog\/wp-content\/themes\/railsware\/vendors\/images\/article-thumbnail-default.jpg","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/3184","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/users\/34"}],"replies":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/comments?post=3184"}],"version-history":[{"count":23,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/3184\/revisions"}],"predecessor-version":[{"id":14136,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/3184\/revisions\/14136"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media\/3196"}],"wp:attachment":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media?parent=3184"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/categories?post=3184"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/tags?post=3184"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/coauthors?post=3184"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}