Skip to content

Instantly share code, notes, and snippets.

@timriley
Created March 24, 2010 03:33
Show Gist options
  • Save timriley/341957 to your computer and use it in GitHub Desktop.
Save timriley/341957 to your computer and use it in GitHub Desktop.

Is it just me, or is it crazy that directly saving a model created via #build or #new on a has_many :through relationship does not create a join model?

See the migrations.rb, models.rb & test_irb_session.txt files below for a concise example of the problem.

This kind of technique is used commonly on nested controllers, and it would work fine for a plain belongs_to or has_many associations. In fact, this behaviour would stop me from using any RESTful controller helpers, like resource_controller.

Is there are way to make it work? Or do I need to look for alternatives, like the below?

s = Subject.first
a = Article.new

# this will save the new article record and create the join model
s.articles << a

The only other place I've found mentioning is this recent bug report

#
# This is my current workaround. See the below files for an example of the problem.
#
# This will be used when nested under a subject
class ArticlesController < ApplicationController
# POST /subjects/1/milestones
def create
@subject = Subject.find(params[:subject_id])
@article = @subject.articles.new(params[:article])
if @article.save
# Now assign it to the subject manually. FIXME: Ugly hack.
@article.subjects << @subject
@article.save!
flash[:notice] = 'Created!'
redirect_to(subjects_articles_path(@subject, @article)
else
render :action => 'new'
end
end
end
class Migrations < ActiveRecord::Migration
def self.up
create_table :articles { |t| t.timestamps }
create_table :subjects { |t| t.timestamps }
create_table :memberships do |t|
t.integer :article_id
t.integer :subject_id
t.timestamps
end
end
end
class Article < ActiveRecord::Base
has_many :memberships
has_many :subjects, :through => :memberships
end
class Subject < ActiveRecord::Base
has_many :memberships
has_many :articles, :through => :memberships
end
class Membership < ActiveRecord::Base
belongs_to :article
belongs_to :subject
end
> subject = Subject.create
Subject Create (0.4ms) INSERT INTO "subjects" ("created_at", "title", "updated_at") VALUES('2010-03-24 03:32:36', NULL, '2010-03-24 03:32:36')
=> #<Subject id: 1, title: nil, created_at: "2010-03-24 03:32:36", updated_at: "2010-03-24 03:32:36">
> article = subject.articles.build
=> #<Article id: nil, title: nil, created_at: nil, updated_at: nil>
> article.save
Article Create (0.5ms) INSERT INTO "articles" ("created_at", "title", "updated_at") VALUES('2010-03-24 03:32:49', NULL, '2010-03-24 03:32:49')
=> true
> subject.reload
Subject Load (0.5ms) SELECT * FROM "subjects" WHERE ("subjects"."id" = 1)
=> #<Subject id: 1, title: nil, created_at: "2010-03-24 03:32:36", updated_at: "2010-03-24 03:32:36">
> subject.articles
Article Load (0.3ms) SELECT "articles".* FROM "articles" INNER JOIN "memberships" ON "articles".id = "memberships".article_id WHERE (("memberships".subject_id = 1))
=> []
> Membership.count
SQL (0.3ms) SELECT count(*) AS count_all FROM "memberships"
=> 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment