validates_uniqueness_of fails when saving directly on the join model - ruby-on-rails

I have three models, Team, Player and TeamMembership. TeamMembership defines the many-to-many relationship between Team and Player. When creating a new Team, the user gets 11 dropdown menus, each containing all the available players. However, a Player can only have a single membership with a Team, which is what I want to validate.
class Player < ActiveRecord::Base
has_many :team_memberships
has_many :teams, :through => :team_memberships
end
class Team < ActiveRecord::Base
has_many :team_memberships
has_many :players, :through => :team_memberships
accepts_nested_attributes_for :players, :team_memberships
validates_associated :team_memberships
end
class TeamMembership < ActiveRecord::Base
belongs_to :team
belongs_to :player
validates_uniqueness_of :player_id, scope: :team_id
end
# GET /teams/new
def new
#team = Team.new
11.times { #team.team_memberships.build }
end
<%= f.fields_for :team_memberships do |team_memberships_form| %>
<%= team_memberships_form.label :player_id %>
<%= team_memberships_form.select(:player_id, options_from_collection_for_select(#Player.available, :id, :name)) %>
<br />
<% end %>
When trying to create a new team, the following appears in the dev log. (Edited down to only 3 players for brevity)
Started POST "/teams" for 127.0.0.1 at 2014-02-06 10:48:40 +0100
Processing by FantasyTeamsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"OwP+nfksvaD0WTQdGjqF5p/shzkiaAodigbFTC6PDD0=", "team"=>{"name"=>"asd", "tournament_id"=>"1", "team_memberships_attributes"=>{"0"=>{"player_id"=>"12"}, "1"=>{"player_id"=>"12"}, "2"=>{"player_id"=>"12"}, "3"=>{"player_id"=>"12"}}}, "commit"=>"Create Fantasy team"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Role Exists (0.3ms) SELECT 1 AS one FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND "roles"."name" = 'admin' LIMIT 1 [["user_id", 1]](0.3ms) BEGIN
FantasyTeamMembership Exists (0.5ms) SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
SQL (0.5ms) INSERT INTO "teams" ("created_at", "name", "tournament_id", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", Thu, 06 Feb 2014 09:48:40 UTC +00:00], ["name", "asd"], ["tournament_id", 1], ["updated_at", Thu, 06 Feb 2014 09:48:40 UTC +00:00], ["user_id", 1]]
SQL (0.4ms) INSERT INTO "team_memberships" ("team_id", "player_id") VALUES ($1, $2) RETURNING "id" [["team_id", 8], ["player_id", 12]]
SQL (0.3ms) INSERT INTO "team_memberships" ("team_id", "player_id") VALUES ($1, $2) RETURNING "id" [["team_id", 8], ["player_id", 12]]
SQL (0.3ms) INSERT INTO "team_memberships" ("team_id", "player_id") VALUES ($1, $2) RETURNING "id" [["team_id", 8], ["player_id", 12]]
(14.7ms) COMMIT
Redirected to http://lolhost:3000/teams/8
Completed 302 Found in 111ms (ActiveRecord: 34.3ms)
As can be seen, because of the way I save the records through accepts_nested_attributes_for, validation does not reflect the actual SQL which will run.
How do I get the behaviour that I want?

Worked around this by adding a custom validation method to the Team model.
validate :unique_players
def unique_players
player_ids = team_memberships.map { |ft| ft.player_id }
if player_ids != player_ids.uniq
errors.add(:team_memberships, "must have unique players.")
end
end

Related

Rails with FactoryGirl, parent-child association. Omit creating one more record in child model

I have two models.
Parent model Tag:
class Tag < ApplicationRecord
has_many :keywords, inverse_of: :tag, dependent: :destroy
accepts_nested_attributes_for :keywords
validates :keywords, presence: true
end
As you can see tag should have at least one keyword.
Child model Keyword:
class Keyword < ApplicationRecord
belongs_to :tag, inverse_of: :keywords
validates :tag, presence: true
end
Here is the code of FactoryGirl factories
tag factory:
FactoryGirl.define do
factory :tag do
sequence(:name) { |n| "Tag#{n}" }
after(:build) do |tag_object|
tag_object.keywords << build(:keyword, tag: tag_object)
end
end
end
keyword factory:
FactoryGirl.define do
factory :keyword do
tag
sequence(:name) { |n| "Keyword#{n}" }
end
end
When I create a new record in keywords table with keyword factory it creates one more record in keywords table which is associated with the same parent record in tags table.
How to omit creating one more record in keywords table and keep factories valid?
irb(main):023:0> FactoryGirl.create :keyword
(0.1ms) BEGIN
Keyword Exists (0.7ms) SELECT 1 AS one FROM "keywords" WHERE "keywords"."name" = $1 LIMIT $2 [["name", "Keyword1"], ["LIMIT", 1]]
Tag Exists (0.3ms) SELECT 1 AS one FROM "tags" WHERE "tags"."name" = $1 LIMIT $2 [["name", "Tag1"], ["LIMIT", 1]]
SQL (0.5ms) INSERT INTO "tags" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "Tag1"], ["created_at", 2017-01-21 19:20:14 UTC], ["updated_at", 2017-01-21 19:20:14 UTC]]
SQL (0.6ms) INSERT INTO "keywords" ("tag_id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["tag_id", 36], ["name", "Keyword1"], ["created_at", 2017-01-21 19:20:14 UTC], ["updated_at", 2017-01-21 19:20:14 UTC]]
(10.4ms) COMMIT
(0.1ms) BEGIN
Keyword Exists (0.4ms) SELECT 1 AS one FROM "keywords" WHERE "keywords"."name" = $1 LIMIT $2 [["name", "Keyword2"], ["LIMIT", 1]]
SQL (0.4ms) INSERT INTO "keywords" ("tag_id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["tag_id", 36], ["name", "Keyword2"], ["created_at", 2017-01-21 19:20:14 UTC], ["updated_at", 2017-01-21 19:20:14 UTC]]
(4.4ms) COMMIT
=> #<Keyword id: 63, tag_id: 36, name: "Keyword2", created_at: "2017-01-21 19:20:14", updated_at: "2017-01-21 19:20:14">
irb(main):024:0>
You can see that it created a record in tags, a record in keywords table, and after that one more record in keywords table.
FactoryGirl creates all the stated associations for the model during the build process. Which means a FactoryGirl.build :keyword will do a FactoryGirl.create :tag so it will have an id for Keyword#tag_id to help pass validations on the Keyword model.
This is consistent with the database activity you are seeing.
irb(main):023:0> FactoryGirl.create :keyword
### keywordA = Keyword.new
### call create(:tag) because of association
### tag1 = Tag.new
### call build(:keyword) in after(:build)
###.keywordB.new(tag: tag1) # which prevents trying to make a new tag!
### tag1.save # which saves the keywordB
(0.1ms) BEGIN
Keyword Exists (0.7ms) SELECT 1 AS one FROM "keywords" WHERE "keywords"."name" = $1 LIMIT $2 [["name", "Keyword1"], ["LIMIT", 1]]
Tag Exists (0.3ms) SELECT 1 AS one FROM "tags" WHERE "tags"."name" = $1 LIMIT $2 [["name", "Tag1"], ["LIMIT", 1]]
SQL (0.5ms) INSERT INTO "tags" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["name", "Tag1"], ["created_at", 2017-01-21 19:20:14 UTC], ["updated_at", 2017-01-21 19:20:14 UTC]]
SQL (0.6ms) INSERT INTO "keywords" ("tag_id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["tag_id", 36], ["name", "Keyword1"], ["created_at", 2017-01-21 19:20:14 UTC], ["updated_at", 2017-01-21 19:20:14 UTC]]
(10.4ms) COMMIT
### keywordA.tag = tag1
### keywordA.save
(0.1ms) BEGIN
Keyword Exists (0.4ms) SELECT 1 AS one FROM "keywords" WHERE "keywords"."name" = $1 LIMIT $2 [["name", "Keyword2"], ["LIMIT", 1]]
SQL (0.4ms) INSERT INTO "keywords" ("tag_id", "name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["tag_id", 36], ["name", "Keyword2"], ["created_at", 2017-01-21 19:20:14 UTC], ["updated_at", 2017-01-21 19:20:14 UTC]]
(4.4ms) COMMIT
### Since keywordA gets saved after keywordB,
### keywordB gets a 1 from the sequence and
### keywordA gets a 2 from the sequence
=> #<Keyword id: 63, tag_id: 36, name: "Keyword2", created_at: "2017-01-21 19:20:14", updated_at: "2017-01-21 19:20:14">
irb(main):024:0>
This is just the gist of what happens. Personally, I cannot imagine wanting a keyword without it's tag based on the database's schema so I would just call create(:tag) and get the first keyword as mentioned before. But the schema is simple enough so the following should hold up in 100% of the situations we would want to test:
FactoryGirl.define do
factory :tag do
sequence(:name) { |n| "Tag#{n}" }
after(:build) do |this|
this.keywords << build(:keyword) if this.keywords.empty?
end
end
end
FactoryGirl.define do
factory :keyword do
sequence(:name) { |n| "Keyword#{n}" }
after(:build) do |this|
this.tag ||= build(:tag)
end
end
end
build(:tag) # unsaved
build(:tag).keyword # also unsaved
create(:tag) # saved
create(:tag).keyword # also saved
build(:keyword) # unsaved
build(:keyword).tag # also unsaved
create(:keyword) # saved
create(:keyword).tag # also saved
# And it still lets you be specific
create(:tag, keywords: [create(:keyword, name: "More of a phrase")])
create(:keyword, tag: create(:tag, name: "Pop Me!"))
A few more options to consider:
# Fake the association
FactoryGirl.define do
factory :keyword do
sequence(:name) { |n| "Keyword#{n}" }
tag_id 1 # Danger!
# Will make it pass validation but you
# will forget and #tag will not be found
# or not what you expect
end
end
# use a trait
FactoryGirl.define do
factory :keyword do
sequence(:name) { |n| "Keyword#{n}" }
trait :with_tag do
tag
end
end
end
# make a new factory
FactoryGirl.define do
# do not need parent if inside the "factory :tag do"
factory :tag_with_keyword, parent: :tag do
sequence(:name) { |n| "Tag#{n}" }
keyword
end
end
# but now we are back to it creating the keyword on build(:tag)
FactoryGirl does give you enough options to solve many situations but the trick is understanding how it sets up the associations and try to stay away from setting up implicit circular ones.
Keywords and tags cannot exist independent of each other. Your tag factory creates a keyword every time it is called, so you should be calling the tag factory. Try this:
tag = FactoryGirl.create(:tag)
keyword = tag.keywords.first

Rails: How to call one-to-one relationship in rails

I'm new to rails and I want to know how to fetch a one-to-one relationship. I want to fetch users city. In my postgresql database I have:
cities Table:
city:varchar
zipcode: integer
users Table
name:varchar
city_id:int
and in city and user model I have:
class City < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :city
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I tried the following in my search controller but didnt work, when logged in:
current_user.city
I get the following error
Processing by SearchController#index as HTML
Parameters: {"utf8"=>"✓", "q"=>"", "criteria"=>"1", "commit"=>"Search"}
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 6 ORDER BY "users"."id" ASC LIMIT 1
PG::UndefinedColumn: ERROR: column cities.user_id does not exist
LINE 1: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" =...
^
: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" = $1 LIMIT 1
Completed 500 Internal Server Error in 11ms
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column cities.user_id does not exist
LINE 1: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" =...
^
: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" = $1 LIMIT 1):
why am I suppose to add a user_id column to cities table, when I have cities foreign key in users table? I dont want to add user_id into cities table.
You can use has_one :through association with join table. Some example for you below.
user model:
class User < ActiveRecord::Base
has_one :city, through: :user_city
has_one :user_city
end
city model:
class City < ActiveRecord::Base
belongs_to :user
end
user city join model:
class UserCity < ActiveRecord::Base
belongs_to :city
belongs_to :user
end
migration for join tables:
class JoinUserCity < ActiveRecord::Migration
def change
create_table :user_cities do |t|
t.integer :user_id
t.integer :city_id
end
end
end
Test in rails console:
=> u = User.create
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-12-07 15:47:14.595728"], ["updated_at", "2014-12-07 15:47:14.595728"]]
(3.3ms) commit transaction
=> #<User id: 4, created_at: "2014-12-07 15:47:14", updated_at: "2014-12-07 15:47:14">
=> u.city
City Load (0.2ms) SELECT "cities".* FROM "cities" INNER JOIN "user_cities" ON "cities"."id" = "user_cities"."city_id" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
=> nil
=> c = City.create
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "cities" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-12-07 15:47:24.535039"], ["updated_at", "2014-12-07 15:47:24.535039"]]
(3.3ms) commit transaction
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
irb(main):004:0> u.city = c
UserCity Load (0.3ms) SELECT "user_cities".* FROM "user_cities" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "user_cities" ("city_id", "user_id") VALUES (?, ?) [["city_id", 1], ["user_id", 4]]
(1.0ms) commit transaction
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
irb(main):005:0> u.save
(0.1ms) begin transaction
(0.1ms) commit transaction
=> true
=> u = User.last
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
=> #<User id: 4, created_at: "2014-12-07 15:47:14", updated_at: "2014-12-07 15:47:14">
=> u.city
City Load (0.2ms) SELECT "cities".* FROM "cities" INNER JOIN "user_cities" ON "cities"."id" = "user_cities"."city_id" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
take a look at the document of has_one and belogns_to,
belongs_to(name, options = {})
Specifies a one-to-one association with another class. This method should only be used if this class
contains the foreign key. If the other class contains the foreign key, then you should use has_one
instead.
as the user table has the foreign key, you should change your model definition like this
class City < ActiveRecord::Base
has_one :user
end
class User < ActiveRecord::Base
belongs_to :city
end

Rails 4: nested attributes and PG::NotNullViolation Error

I have a model User.rb that accepts_nested_attributes_for :address
user.rb
has_one :address
accepts_nested_attributes_for :address
address.rb
belongs_to :user
When I try to test it using Rails console the following happens
user = User.find(157)
User Load (1.5ms) SELECT "users". FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 157]]*
#<User id: 157, name: "John Doe", email: ...
user.address.phone
UserAddress Load (0.8ms) SELECT "addresses". FROM "addresses" WHERE "addresses"."type" IN ('UserAddress') AND "addresses"."user_id" = $1 ORDER BY "addresses"."id" ASC LIMIT 1 [["user_id", 157]]
"1234567"
That's fine so far. However, the following does not work:
user.update(:address_attributes => {:phone => "888888"})
It throws
ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR: null value in column "user_id" violates not-null constraint
The SQL doesn't make much sense to me
UPDATE "addresses" SET "user_id" = $1, "updated_at" = $2 WHERE "addresses"."type" IN ('UserAddress') AND "addresses"."id" = 128 [["user_id", nil], ["updated_at", Sun, 02 Feb 2014 19:55:07 CET +01:00]]
Why does it try to update user_id with nil when I actually updated the phone attribute?
Perhaps the issue is that you're not using the correct ActiveRecord object?
Maybe you could try:
user.address.update_attributes({phone: "888888"})

Why am I getting an undefined method error in rails 4 with this simple create action?

I have found some similar questions on stack overflow, but nothing that helps. I have a user model. I have a profile model that belongs to the user model. I have a job model that belongs to the profile model. I am making a simple form to create a job. When i submit the form in the browser, I am given the error:
undefined method `build_job' for #<Student:0x007f8309023530>
And it shows the create action in the jobs controller:
def create
job = current_user.build_job(job_params)
job.save
redirect_to profile_path(current_user.profile_name)
end
The jobs create method is identical to the profiles create method, with the word profile replaced with job, so I can't figure out why its not working. My guess is it has something to do with jobs belonging to a model that belongs to another model. How do I fix this? Also, here is the job_params method:
def profile_params
params.require(:profile).permit(:title, :category, :description, :state, :zip_code, :rate, jobs_attributes: [:firm, :position])
end
And here are my models:
Job:
class Job < ActiveRecord::Base
belongs_to :profile
end
Profile:
class Profile < ActiveRecord::Base
belongs_to :user
has_many :jobs, :dependent => :destroy
end
User:
class User < ActiveRecord::Base
has_one :profile
end
Reference in view:
<%= #user.profile.job.firm if #user.profile.try(:job)%>
I am also adding my server log from clicking on submit. Hope it helps answer the question:
Started POST "/jobs" for 127.0.0.1 at 2013-10-27 21:45:06 -0400
ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by JobsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"VRqIuzR1x6tE/G+/wzrG1iFBOEDE7mgsfyjokX7wNZo=", "job"=>{"firm"=>"signat", "position"=>""}, "commit"=>"Save"}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
(0.2ms) BEGIN
SQL (3.4ms) INSERT INTO "jobs" ("created_at", "firm", "position", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["created_at", Mon, 28 Oct 2013 01:45:06 UTC +00:00], ["firm", "signat"], ["position", ""], ["updated_at", Mon, 28 Oct 2013 01:45:06 UTC +00:00]]
(0.4ms) COMMIT
Redirected to http://localhost:3000/profiles/philip7899
Completed 302 Found in 209ms (ActiveRecord: 9.8ms)
Started GET "/profiles/philip7899" for 127.0.0.1 at 2013-10-27 21:45:06 -0400
Processing by ProfilesController#show as HTML
Parameters: {"id"=>"philip7899"}
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."profile_name" = 'philip7899' ORDER BY "users"."id" ASC LIMIT 1
Profile Load (0.8ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 ORDER BY "profiles"."id" ASC LIMIT 1 [["user_id", 1]]
School Load (0.9ms) SELECT "schools".* FROM "schools" WHERE "schools"."id" = $1 ORDER BY "schools"."id" ASC LIMIT 1 [["id", 1]]
Job Exists (0.6ms) SELECT 1 AS one FROM "jobs" WHERE "jobs"."profile_id" = $1 LIMIT 1 [["profile_id", 1]]
Rendered profiles/_full_profile.html.erb (92.4ms)
Rendered profiles/show.html.erb within layouts/application (95.4ms)
Rendered layouts/_ssi_header_inner.html.erb (4.2ms)
Rendered layouts/_ssi_footer.html.erb (0.2ms)
Completed 200 OK in 218ms (Views: 209.4ms | ActiveRecord: 5.9ms)
Couple of problems. You need to define has_many jobs on user, and the correct method for building has_many is association.build not build_association:
class User
has_many :jobs, through: :profile
end
job = current_user.jobs.build(job_params)

Losing an Attribute When Saving Through an Association w/ Scope (Rails 4.0.0)

The Code (Rails 4.0.0)
class Track < ActiveRecord::Base
has_many :artist_tracks
has_many :owning_artists,
-> { where(:artist_tracks => { :artistic_role_id => 1 }) },
:through => :artist_tracks,
:source => :artist
end
class ArtistTrack < ActiveRecord::Base
belongs_to :artist
belongs_to :track
belongs_to :artistic_role
end
class Artist < ActiveRecord::Base
has_many :artist_tracks
has_many :tracks, :through => :artist_tracks
end
Finding Works
# artist_tracks.artistic_role_id is properly set to "1"
2.0.0p195 :003 > Track.last.owning_artists
Track Load (1.1ms) SELECT "tracks".* FROM "tracks" ORDER BY "tracks"."id" DESC LIMIT 1
Artist Load (0.8ms) SELECT "artists".* FROM "artists" INNER JOIN "artist_tracks" ON "artists"."id" = "artist_tracks"."artist_id" WHERE "artist_tracks"."artistic_role_id" = 1 AND "artist_tracks"."track_id" = $1 [["track_id", 10]]
Create Does Not Work
# artist_tracks.artistic_role_id is totally missing from the INSERT
2.0.0p195 :005 > Track.create!(name: "test_name", lyrics: "test_lyrics", owning_artist_ids: [1])
Artist Load (1.3ms) SELECT "artists".* FROM "artists" WHERE "artists"."id" = $1 LIMIT 1 [["id", 1]]
(0.5ms) BEGIN
Artist Exists (0.7ms) SELECT 1 AS one FROM "artists" WHERE ("artists"."name" = 'TestArtist1' AND "artists"."id" != 1) LIMIT 1
SQL (0.7ms) INSERT INTO "tracks" ("created_at", "lyrics", "name", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["created_at", Thu, 13 Jun 2013 22:20:14 UTC +00:00], ["lyrics", "test_lyrics"], ["name", "test_name"], ["updated_at", Thu, 13 Jun 2013 22:20:14 UTC +00:00]]
#
# Y U NO have artist_tracks.artistic_role_id?
#
SQL (0.7ms) INSERT INTO "artist_tracks" ("artist_id", "created_at", "track_id", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["artist_id", 1], ["created_at", Thu, 13 Jun 2013 22:20:14 UTC +00:00], ["track_id", 12], ["updated_at", Thu, 13 Jun 2013 22:20:14 UTC +00:00]]
(1.0ms) COMMIT
According to the Rails Guide for Active Record Associations (4.3.3.1 where), I believe my usage of the scope and expectation are valid:
If you use a hash-style where option, then record creation via this
association will be automatically scoped using the hash.
Why is the artist_tracks.artistic_role_id attribute being lost? If my expectations are wrong, I'd like to understand why and how to implement an alternative solution.
I have also listed this as an issue on the Rails repo. Any insight is appreciated! Thank you
I believe that what is happening is that the associated model actually being created here is the join model, artist_tracks, and not the association with the actual conditions on it. You could probably fix this by declaring an alternate join association with conditions on it, and then attaching owning_artists through that instead. Like this:
class Track < ActiveRecord::Base
has_many :artist_tracks
has_many :owning_artist_tracks,
-> { where(:artistic_role_id => 1) },
:class_name => "ArtistTrack"
has_many :owning_artists,
:through => :owning_artist_tracks,
:source => :artist
end

Resources