I'm trying to model a system where each user may have many emails (at least one).
Following good normalization rules I created two migrations (some fields removed for brevity):
create_table :users do |t|
end
create_table :user_emails do |t|
t.integer :user_id, null: false
t.string :email, null: false
end
add_index :user_emails, :email, :unique => true
add_foreign_key :user_emails, :users, dependent: :delete
and the following rails models:
class User < ActiveRecord::Base
has_many :emails, class_name: 'UserEmail', dependent: :destroy
def self.find_by_email(email)
UserEmail.find_by(email: email).try(:user)
end
validate do
if emails.count < 1
errors.add(:emails, "is empty")
end
end
end
class UserEmail < ActiveRecord::Base
belongs_to :user
validates_presence_of :user_id, :email
validates_uniqueness_of :email
end
Now I am not able to create any of those. User cannot be created since it requires at least an UserEmail. At the same time, UserEmail cannot be created beforehand since it requires an user_id.
I believe I have tried any combination of #user.emails.build and #user.emails << e that I can think of.
How can I solve this really simple problem without renouncing to data consistency (one is saved and the other is not)?
P.s.: I tought that maybe relaxing the validations and using transactions may solve the problem consistently. However I've never used transactions in rails, so any help is really appreciated.
Thanks
validates_presence_of :user_id only check for any valid integer which might not be a valid user.
But if you use validates_presence_of :user and validates_presence_of :emails, they will check the user and emails association are valid and not blank.
Also, when you are trying to create the user and the associated email, you are able to do the following code on application level.
user = User.new(name: 'user name')
user.emails.build(email_address: 'email address') #build(email: '') for your case.
Then, you can save to database with
user.save!
Below is the code I tested with.
class User < ActiveRecord::Base
has_many :emails, class_name: 'UserEmail', dependent: :destroy
validates_presence_of :emails, :message => 'User should have at least one email address.'
end
class UserEmail < ActiveRecord::Base
belongs_to :user
validates_presence_of :user
validates_presence_of :email_address
end
[40] pry(main)> u = User.create!(name: 'doh')
(0.1ms) begin transaction
(0.0ms) rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Emails User should have at least one email address.
[1] pry(main)> u = User.new(name: 'nice')
=> #<User id: nil, name: "nice", created_at: nil, updated_at: nil>
[2] pry(main)> u.emails.build(email_address: 'hello#world.blah')
=> #<UserEmail id: nil, user_id: nil, email_address: "hello#world.blah", created_at: nil, updated_at: nil>
[3] pry(main)> u.save!
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "users" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", "2014-07-26 10:14:52.184245"], ["name", "nice"], ["updated_at", "2014-07-26 10:14:52.184245"]]
SQL (0.2ms) INSERT INTO "user_emails" ("created_at", "email_address", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["created_at", "2014-07-26 10:14:52.189757"], ["email_address", "hello#world.blah"], ["updated_at", "2014-07-26 10:14:52.189757"], ["user_id", 5]]
(0.7ms) commit transaction
=> true
[4] pry(main)> u.emails.count
(0.2ms) SELECT COUNT(*) FROM "user_emails" WHERE "user_emails"."user_id" = ? [["user_id", 5]]
=> 1
[5] pry(main)> u.id
=> 5
[6] pry(main)> u.name
=> "nice"
[7] pry(main)> u.emails
=> [#<UserEmail id: 4, user_id: 5, email_address: "hello#world.blah", created_at: "2014-07-26 10:14:52", updated_at: "2014-07-26 10:14:52">]
[8] pry(main)> u
=> #<User id: 5, name: "nice", created_at: "2014-07-26 10:14:52", updated_at: "2014-07-26 10:14:52">
[19] pry(main)> UserEmail.create!(email_address: 'test#test.org')
(0.1ms) begin transaction
(0.1ms) rollback transaction
ActiveRecord::RecordInvalid: Validation failed: User can't be blank
Hope this helps.
I just realized that I adding a NOT NULL constraint on the storage layer is sufficient. I can remove the :user_id presence validation and have the same consistency behavior, with the exception that it now works.
However this looks quite hacky from the rails POW. Any better solution is still really appreciated...
Related
I'm trying to migrate my project from Rails 5.0 to 5.2
Project extensively uses creation of related models through .build_%related_model%, it was working on rails 5.0 and now it's broke.
Does this functionality removed, or should i use another syntax?
class User < ActiveRecord::Base
belongs_to :profile, inverse_of: :user
end
class Profile < ActiveRecord::Base
has_one :user, inverse_of: :profile
end
new_user = User.new
new_user.build_profile
new_user.save
Previously this code created both User and his Profile. Now this will create only User, without Profile.
Any ideas how to fix this?
irb(main):001:0> new_user = User.new
=> #<User id: nil, profile_id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> new_user.build_profile
=> #<Profile id: nil, created_at: nil, updated_at: nil>
irb(main):003:0> new_user.save
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "profiles" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2018-04-21 13:16:23.669286"], ["updated_at", "2018-04-21 13:16:23.669286"]]
Profile Load (0.2ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SQL (0.2ms) INSERT INTO "users" ("profile_id", "created_at", "updated_at") VALUES (?, ?, ?) [["profile_id", 1], ["created_at", "2018-04-21 13:16:23.691292"], ["updated_at", "2018-04-21 13:16:23.691292"]]
(181.1ms) commit transaction
=> true
class CreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
t.integer :profile_id
t.timestamps
end
end
end
class CreateProfiles < ActiveRecord::Migration[5.1]
def change
create_table :profiles do |t|
t.timestamps
end
end
end
class User < ApplicationRecord
belongs_to :profile, inverse_of: :user
end
class Profile < ApplicationRecord
has_one :user, inverse_of: :profile
end
tested it out all worked. Copied code to answer since its not readable in comment. Your problem must be somewhere else do u get any errors or paste migration files to under question
accepts_nested_attributes_for :profile fixed this exact issue, but many other have popped up.
I had to stop this update and rollback everything.
I'm currently trying to implement a Category model to my application. I'm trying to design it in a way that Users can have many Categories, and so can Groups.
The problem I'm running into is that I also want to be able to just have a normal list of Categories without them being assigned to any User or Group.
I was referencing rubyonrails.org/association_basics.
class CreateCategories < ActiveRecord::Migration[5.0]
def change
create_table :categories do |t|
t.string :name
t.text :description
t.references :categorizable, polymorphic: true, index: true
t.timestamps
end
end
end
class Category < ApplicationRecord
belongs_to :categorizable, :polymorphic => true
end
class User < ApplicationRecord
has_many :categories, :as => :categorizable
end
class Group< ApplicationRecord
has_many :categories, :as => :categorizable
end
I'm trying to create a new Category through rails c, but whenever I try to save, it rolls back my transaction probably because I'm missing some condition.
Category(id: integer, name: string, description: text, created_at: datetime, updated_at: datetime)
Category.create( :id => 1, :name => 'Category_1', :description => '' )
begin transaction
rollback transaction
I also feel like there is a better way to create a new Category, as I shouldn't be setting the id manually.
Thanks for your help.
In rails 5, whenever you define a belongs_to association, it is required to have the associated record present by default. You would see this when you look at the errors after trying to create the category object
category = Category.create(:name => 'Category_1', :description => '' )
category.errors.full_messages.to_sentence
If you want to be able to save a record without the belongs_to association, you would have to specify it explicitly
class Category < ApplicationRecord
belongs_to :categorizable, polymorphic: true, required: false
end
If you try to create a new category and see the error is that there needs to exists a categorizable record in order for the category to be created, an easy way to do it is to put the new object itself as the categorizable one and it should do the trick.
$ category = Category.new
=> #<Category id: nil, name: nil, description: nil, categorizable_type: nil, categorizable_id: nil, created_at: nil, updated_at: nil>
$ category.save
(0.1ms) begin transaction
(0.1ms) rollback transaction
=> false
$ category.errors.full_messages
=> ["Categorizable must exist"]
$ category = Category.new(categorizable: category)
=> #<Category id: nil, name: nil, description: nil, categorizable_type: "Category", categorizable_id: nil, created_at: nil, updated_at: nil>
$ category.save
(0.1ms) begin transaction
SQL (1.3ms) INSERT INTO "categories" ("categorizable_type", "created_at", "updated_at") VALUES (?, ?, ?) [["categorizable_type", "Category"], ["created_at", 2017-01-15 00:08:55 UTC], ["updated_at", 2017-01-15 00:08:55 UTC]]
(0.7ms) commit transaction
=> true
This should help, Rails Cast on Polymorphic
https://www.youtube.com/watch?v=6l9EAuev16k
You can create polymorphic records with this...
`#category = #categorizable.User.new`
`#category = #categorizable.Group.new`
So you do not need the id.
I've been working on implementing a new model that belongs to one of our web apps existing models. Eventually, I want to build out a nested form. I understand that the form, and strong params can have it's own suite of issues, but I am currently struggling to get the models to behave as I would expect in the rails console.
Rails 4.2.7, Postgres DB
UPDATE - 10/3/16 - Still trying to find the right solution, but have made some changes
Our work is with Schools and Districts, and this particular case deals with surveys and how a survey is assigned to a school and district. Until now, a survey has been assigned to a district with a SurveyAssignment model, and some down the line logic assumed that all schools in a district were also "assigned" to the survey. Now, we want to be able to add more granularity to the SurveyAssignment and allow some specificity at the school level.
So I created a SchoolSurveyAssignment model and started to get the bits in place.
Here is the relevant model info:
class District < ActiveRecord::Base
...
has_many :schools, dependent: :destroy
has_many :survey_assignments, dependent: :destroy
...
end
class School
...
belongs_to :district
has_many :school_survey_assignments
has_many :survey_assignments, :through => :school_survey_assignments
...
end
class SurveyAssignment
belongs_to :district
belongs_to :survey
has_one :survey_version, through: :survey
has_many :school_survey_assignments, inverse_of: survey_assignment
has_many :schools, :through => :school_survey_assignments
accepts_nested_attributes_for :school_survey_assignments
attr_accessor :survey_group, :survey_version_type, :survey_version_id, :school_survey_assignments_attributes
validates :survey_id, presence: true
end
class SchoolSurveyAssignment
belongs_to :survey_assignment, inverse_of: :school_survey_assignments
belongs_to :school
attr_accessor :school_id, :survey_assignment_id, :grades_affected, :ulc_affected
validates_presence_of :survey_assignment
validates :school_id, presence: true, uniqueness: {scope: :survey_assignment_id}
end
Relevant Controller code:
class SurveyAssignmentsController < ApplicationController
before_action :set_district
before_action :set_survey_assignment, only: [:show, :edit, :update, :destroy]
respond_to :html, :json, :js
def new
#new_survey_assignment = SurveyAssignment.new()
#district.schools.each do |school|
#new_survey_assignment.school_survey_assignments.build(school_id: school.id)
end
end
def create
#survey_assignment = SurveyAssignment.new(survey_assignment_params)
if #survey_assignment.save
flash[:notice] = "Survey successfully assigned to #{#district.name}"
else
flash[:alert] = "There was a problem assigning this survey to #{#district.name}"
end
redirect_to district_survey_assignments_path(#district)
end
def survey_assignment_params
params.require(:survey_assignment).permit(:survey_id, :status, :survey_version_id, school_survey_assignments_attributes: [:id, :survey_assignment_id, :school_id, grades_affected: [], ulc_affected: []]).tap do |p|
p[:district_id] = #district.id
p[:school_year] = session[:selected_year]
end
end
def set_district
#district = District.find(params[:district_id])
end
Here is the relevant schema info:
create_table "school_survey_assignments", force: :cascade do |t|
t.integer "survey_assignment_id"
t.integer "school_id"
t.integer "grades_affected", default: [], array: true
t.string "ulc_affected", default: [], array: true
end
add_index "school_survey_assignments", ["school_id"], name: "index_school_survey_assignments_on_school_id", using: :btree
add_index "school_survey_assignments", ["survey_assignment_id"], name: "index_school_survey_assignments_on_survey_assignment_id", using: :btree
create_table "survey_assignments", force: :cascade do |t|
t.integer "district_id"
t.integer "survey_id"
t.integer "status"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "school_year"
t.integer "last_response_status_id"
end
add_index "survey_assignments", ["district_id"], name: "index_survey_assignments_on_district_id", using: :btree
Once these were in place, I stepped into my rails console and attempted the following:
2.3.1 :002 > sa1 = SurveyAssignment.create(district_id: 3, survey_id: 508, school_year: 2017)
(0.2ms) BEGIN
SQL (0.7ms) INSERT INTO "survey_assignments" ("district_id", "survey_id", "school_year", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["district_id", 3], ["survey_id", 508], ["school_year", 2017], ["created_at", "2016-09-30 21:30:20.205144"], ["updated_at", "2016-09-30 21:30:20.205144"]]
(7.2ms) COMMIT
=> #<SurveyAssignment id: 369, district_id: 3, survey_id: 508, status: nil, created_at: "2016-09-30 21:30:20", updated_at: "2016-09-30 21:30:20", school_year: 2017, last_response_status_id: nil>
2.3.1 :003 > sa2 = SurveyAssignment.create(district_id: 3, survey_id: 508, school_year: 2017)
(0.3ms) BEGIN
SQL (0.4ms) INSERT INTO "survey_assignments" ("district_id", "survey_id", "school_year", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["district_id", 3], ["survey_id", 508], ["school_year", 2017], ["created_at", "2016-09-30 21:30:30.701197"], ["updated_at", "2016-09-30 21:30:30.701197"]]
(0.5ms) COMMIT
=> #<SurveyAssignment id: 370, district_id: 3, survey_id: 508, status: nil, created_at: "2016-09-30 21:30:30", updated_at: "2016-09-30 21:30:30", school_year: 2017, last_response_status_id: nil>
So now, I've successfully created two Survey Assignments. I'm now going to create two School Survey Assignments off of sa1:
2.3.1 :004 > [{school_id: 5}, {school_id: 6}].each do |ssa|
2.3.1 :005 > sa1.school_survey_assignments.create(ssa)
2.3.1 :006?> end
(0.2ms) BEGIN
SchoolSurveyAssignment Exists (2.4ms) SELECT 1 AS one FROM "school_survey_assignments" WHERE ("school_survey_assignments"."school_id" = 5 AND "school_survey_assignments"."survey_assignment_id" = 369) LIMIT 1
SQL (0.4ms) INSERT INTO "school_survey_assignments" ("survey_assignment_id") VALUES ($1) RETURNING "id" [["survey_assignment_id", 369]]
(6.4ms) COMMIT
(0.6ms) BEGIN
SchoolSurveyAssignment Exists (0.4ms) SELECT 1 AS one FROM "school_survey_assignments" WHERE ("school_survey_assignments"."school_id" = 6 AND "school_survey_assignments"."survey_assignment_id" = 369) LIMIT 1
SQL (0.3ms) INSERT INTO "school_survey_assignments" ("survey_assignment_id") VALUES ($1) RETURNING "id" [["survey_assignment_id", 369]]
(0.4ms) COMMIT
=> [{:school_id=>5}, {:school_id=>6}]
2.3.1 :007 > sa1.save
(0.3ms) BEGIN
(0.4ms) COMMIT
=> true
Now, it looks like I've successfully created two SchoolSurveyAssignments with survey_assignment_id = 369 and school_ids = 5 and 6
2.3.1 :008 > sa1.school_survey_assignments
SchoolSurveyAssignment Load (0.3ms) SELECT "school_survey_assignments".* FROM "school_survey_assignments" WHERE "school_survey_assignments"."survey_assignment_id" = $1 [["survey_assignment_id", 369]]
=> #<ActiveRecord::Associations::CollectionProxy [#<SchoolSurveyAssignment id: 5, survey_assignment_id: 369, school_id: nil, grades_affected: [], ulc_affected: []>, #<SchoolSurveyAssignment id: 6, survey_assignment_id: 369, school_id: nil, grades_affected: [], ulc_affected: []>]>
As you can see from the ActivRecord::Associations::CollectionProxy, both of the SchoolSurveyAssignments were created, with survey_assignment_id: 369, but with a nil school_id. This is troubling as it seems to be
Ignoring the parameters being passed into the create function, and
ignoring the validation of school_id
Another item that I don't understand is the following:
2.3.1 :009 > SchoolSurveyAssignment.find(5).survey_assignment_id
SchoolSurveyAssignment Load (0.6ms) SELECT "school_survey_assignments".* FROM "school_survey_assignments" WHERE "school_survey_assignments"."id" = $1 LIMIT 1 [["id", 5]]
=> nil
2.3.1 :011 > SchoolSurveyAssignment.find(5).survey_assignment.id
SchoolSurveyAssignment Load (0.3ms) SELECT "school_survey_assignments".* FROM "school_survey_assignments" WHERE "school_survey_assignments"."id" = $1 LIMIT 1 [["id", 5]]
SurveyAssignment Load (0.4ms) SELECT "survey_assignments".* FROM "survey_assignments" WHERE "survey_assignments"."id" = $1 LIMIT 1 [["id", 369]]
=> 369
Calling .survey_assignment_id should return the attribute on the SchoolSurveyAssignment and give 369. .survey_assignment.id is simply just grabbing the parent object's ID. I would expect both to return the same value, but one returns nil.
The end use case is making a SurveyAssignment form that lets the user set the attributes for a new SurveyAssignment and also set the attributes for X number of SchoolSurveyAssignments (based on # of schools in a district; varies from 2 to 15). Once I get a better grasp on how these models are interacting, I feel confident in executing this goal, but the behavior I'm seeing doesn't make sense to me, and I was hoping to find some clarity on implementing these related models. I feel like I'm bouncing around the answer, but am missing a key detail.
Thanks,
Alex
Try removing your attr_accessor lines of code. attr_accessor shouldn't be used for attributes that are persisted in the database and it's probably messing up the methods that ActiveRecord already provides by default, causing those attributes to not be saved properly
class SurveyAssignment
belongs_to :district
belongs_to :survey
has_one :survey_version, through: :survey
has_many :school_survey_assignments, inverse_of: survey_assignment
has_many :schools, :through => :school_survey_assignments
accepts_nested_attributes_for :school_survey_assignments
validates :survey_id, presence: true
end
class SchoolSurveyAssignment
belongs_to :survey_assignment, inverse_of: :school_survey_assignments
belongs_to :school
validates_presence_of :survey_assignment
validates :school_id, presence: true, uniqueness: {scope: :survey_assignment_id}
end
For the first question, School and SurveyAssignment don't know each other, school_id becomes nil. In your app, these models have m-to-n association indirectly, so how about using has_many through association between models?
In School model, add below:
has_many :survey_assignments, :through => :school_survey_assignments
In SurveyAssignments model, add below:
has_many :schools, :through => :school_survey_assignments
For the last question, both codes seem to be same..
I have a User model which has many roles. Roles contains a user_id field, which I want to validate_presence_of
The issue is: if I assign a role to user upon create, the validation fails because no user_id is set. Now, I do want to validate that a user_id exists, but I need to save the user before checking that.
The code currently looks like this:
#user = User.new(params[:user])
#user.roles << Role.new(:name => 'Peon') unless #user.has_roles?
if #user.save
# ...
The only ways I can think of getting around the problem involves either disabling the validation, which I don't want to do, or double-saving to the DB, which isn't exactly efficient.
What's the standard way for handling this issue?
After researching a bit, this solution seems to be easiest. First, in your Role model, instead of validating user_id, validate user:
validates :user, :presence => true
Then, in your User model, add :inverse_of => :user to your has_many call:
has_many :roles, :inverse_of => :user
Then it works as expected:
irb(main):001:0> #user = User.new
=> #<User id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> #user.roles << Role.new(:name => "blah")
=> [#<Role id: nil, user_id: nil, name: "blah", created_at: nil, updated_at: nil>]
irb(main):003:0> #user.roles[0].user
=> #<User id: nil, created_at: nil, updated_at: nil>
irb(main):004:0> #user.save
(0.1ms) begin transaction
SQL (3.3ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Fri, 04 Jan 2013 02:29:33 UTC +00:00], ["updated_at", Fri, 04 Jan 2013 02:29:33 UTC +00:00]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
SQL (0.2ms) INSERT INTO "roles" ("created_at", "name", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["created_at", Fri, 04 Jan 2013 02:29:34 UTC +00:00], ["name", "blah"], ["updated_at", Fri, 04 Jan 2013 02:29:34 UTC +00:00], ["user_id", 3]]
(1.9ms) commit transaction
=> true
irb(main):005:0> #user.roles.first
=> #<Role id: 4, user_id: 3, name: "blah", created_at: "2013-01-04 02:29:34", updated_at: "2013-01-04 02:29:34">
Note, however, that this still produces two SQL transactions, one to save the user and one to save the role. I don't see how you can avoid that.
See also: How can you validate the presence of a belongs to association with Rails?
I think you can get around the validation problem if you change your code to look like this:
#user = User.new(params[:user])
#user.roles.new(:name => 'Peon') unless #user.has_roles?
if #user.save
# ...
If that doesn't work, you could try changing you validation to this:
class Role < ActiveRecord::Base
belongs_to :user
validates :user_id, :presence => true, :unless => Proc.new() {|r| r.user}
end
You must take a look at ActiveRecord's Callbacks. Probably you will use the before_validation to do it.
For anyone Googling for a solution to this problem for a has_many :through association, as of 5/December/2013 the :inverse_of option can't be used in conjunction with :through (source). Instead, you can use the approach suggested by #waldyr.ar. For example, if our models are set up as follows:
class User < ActiveRecord::Base
has_many :roles
has_many :tasks, through: roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :task
end
class Task < ActiveRecord::Base
has_many :roles
has_many :users, through: roles
end
We can modify our Role class as follows to validate the presence of both task and user before saving
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :task
before_save { validates_presence_of :user, :task }
end
Now if we create a new User and add a couple tasks like so:
>> u = User.new
>> 2.times { u.tasks << Task.new }
Running u.save will save the User and the Task, as well as transparently build and save a new Role whose foreign keys user_id and task_id are set appropriately. Validations will run for all models, and we can go on our merry way!
(I could probably think of a better title for this and open to suggestions)
I am trying to call this in my NotesController, testing it in rails console:
?> u = User.first
User Load (1.6ms) SELECT "users".* FROM "users" LIMIT 1
=> #<User id: 2, email: nil, password: nil, linkedin_url: nil, created_at: "2012-06-17 05:54:44", updated_at: "2012-06-17 05:54:44", liid: "7fB-pQGIQi">
>> c = u.contacts.first
Contact Load (2.0ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."user_id" = 2 LIMIT 1
=> #<Contact id: 8, user_id: 2, created_at: "2012-06-19 01:23:45", updated_at: "2012-06-19 01:23:45">
>> c.notes.create!(:body => "this is a note")
(0.5ms) BEGIN
SQL (23.3ms) INSERT INTO "notes" ("body", "contact_id", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["body", "this is a note"], ["contact_id", 8], ["created_at", Thu, 21 Jun 2012 05:42:21 UTC +00:00], ["updated_at", Thu, 21 Jun 2012 05:42:21 UTC +00:00], ["user_id", nil]]
(1.7ms) COMMIT
=> #<Note id: 4, created_at: "2012-06-21 05:42:21", updated_at: "2012-06-21 05:42:21", body: "this is a note", user_id: nil, contact_id: 8>
The problem is in the last line where it says that the Note created has a "user_id: nil". I'm wondering what I'm missing that is not allowing the note to properly get the user_id from the contact user_id? I can think of a quick fix, to set the user_id on the note object, but it seems as though it could fetch it from the contact_id, am I wrong?
Here are my models in case this is helpful:
class Contact < ActiveRecord::Base
attr_accessible :user_id
belongs_to :user
has_many :notes
end
class User < ActiveRecord::Base
attr_accessible :password, :liid
has_many :contacts
has_many :notes, :through => :contacts
end
class Note < ActiveRecord::Base
attr_accessible :title, :body
belongs_to :contact
belongs_to :user
end
Thanks for the help!
Your Note also needs to belong to your User:
class Note < ActiveRecord::Base
attr_accessible :title, :body
belongs_to :contact
belongs_to :user
end
Rails will only automatically set the foreign_key of the parent object, and not the parent object's parent like you want. So you'll have to set that attribute manually:
c.notes.create!(:body => "this is a note", :user_id => c.user_id)