2012-05-29 108 views
1

我有幾周的經驗或接近一個月的Ruby on Rails學習。我希望理解爲什麼我不能通過關聯對象獲取方法。如何通過has_one和belongs_to關聯獲取方法?

我正試圖將相關的對象附加到用戶,而不是單獨使用Profile.new例如其方法如下所示。

user.profile.create

user.profile.create!

user.profile.build

,而不是我得到RSpec的錯誤消息。 NoMethodError:對於無未定義的方法`編譯」:NilClass

感謝好心提前

# == Schema Information 
# 
# Table name: users 
# 
# id   :integer   not null, primary key 
# email  :string(255) 
# created_at :datetime  not null 
# updated_at :datetime  not null 
# 

class User < ActiveRecord::Base 
    attr_accessible :email 
    has_one :profile 

    before_save { |user| user.email = email.downcase } 

    VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i 
    validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, 
        uniqueness: { case_sensitive: false } 
end 

# == Schema Information 
    # 
    # Table name: profiles 
    # 
    # id   :integer   not null, primary key 
    # given_name :string(255) 
    # surname :string(255) 
    # user_id :integer 
    # created_at :datetime  not null 
    # updated_at :datetime  not null 
    # 

    class Profile < ActiveRecord::Base 
     attr_accessible :given_name, :surname #, :user_id 
     belongs_to :user 

     validates :user_id, presence: true 
    end 

[email protected]:~/rails_projects/bffmApp$ bundle exec guard 
    Guard uses Libnotify to send notifications. 
    Guard is now watching at '/home/smileymike/rails_projects/bffmApp' 
    Starting Spork for RSpec 
    Using RSpec 
    Preloading Rails environment 
    Loading Spork.prefork block... 
    Spork is ready and listening on 8989! 
    Spork server for RSpec successfully started 
    Guard::RSpec is running, with RSpec 2! 
    Running all specs 
    Running tests with args ["--drb", "-f", "progress", "-r", "/home/smileymike/.rvm/gems/ruby-1.9.3-p194/gems/guard-rspec-0.7.2/lib/guard/rspec/formatters/notification_rspec.rb", "-f", "Guard::RSpec::Formatter::NotificationRSpec", "--out", "/dev/null", "--failure-exit-code", "2", "spec"]... 
    ......FFFFFFFF............... 

    Failures: 

     1) Profile 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

     2) Profile 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

     3) Profile 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

     4) Profile 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

     5) Profile 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

     6) Profile user 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

     7) Profile when user_id is not present 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

     8) Profile accessible attributes should not allow access to user_id 
     Failure/Error: before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 
     NoMethodError: 
      undefined method `build' for nil:NilClass 
     # ./spec/models/profile_spec.rb:23:in `block (2 levels) in <top (required)>' 

    Finished in 1.56 seconds 
    29 examples, 8 failures 

    Failed examples: 

    rspec ./spec/models/profile_spec.rb:27 # Profile 
    rspec ./spec/models/profile_spec.rb:28 # Profile 
    rspec ./spec/models/profile_spec.rb:29 # Profile 
    rspec ./spec/models/profile_spec.rb:30 # Profile 
    rspec ./spec/models/profile_spec.rb:33 # Profile 
    rspec ./spec/models/profile_spec.rb:31 # Profile user 
    rspec ./spec/models/profile_spec.rb:37 # Profile when user_id is not present 
    rspec ./spec/models/profile_spec.rb:41 # Profile accessible attributes should not allow access to user_id 
    Done. 

    > 

require 'spec_helper' 

describe Profile do 

# before do 
    # This code is wrong but it works 
# @profile = Profile.new(given_name: "Michael", surname: "Colin", user_id: user.id) 
# end 
# but I am attempting to create a profile via User/Profile assoications 
    let(:user) { FactoryGirl.create(:user) } 
    before { @profile = user.profile.build(given_name: "Michael", surname: "Colin") } 

    subject { @profile } 

    it { should respond_to(:given_name) } 
    it { should respond_to(:surname) } 
    it { should respond_to(:user_id) } 
    it { should respond_to(:user) } 
    its(:user) { should == user } 

    it { should be_valid } 

    describe "when user_id is not present" do 
    before { @profile.user_id = nil } 
    it { should_not be_valid } 
    end 

    describe "accessible attributes" do 
    it "should not allow access to user_id" do 
     expect do 
     Profile.new(user_id: user_id) 
     end.should raise_error(ActiveModel::MassAssignmentSecurity::Error) 
    end  
    end 
end 

回答

3

has_one會爲您提供用戶的build_profile方法。有關更多詳細信息,請參閱http://guides.rubyonrails.org/association_basics.html#has_one-association-reference

你不能做user.profile.build的原因是沒有配置文件,所以user.build返回零,它沒有任何意義要求無建立一個配置文件。這與has_many的情況不同,哪裏總是返回一些東西 - 即使集合是空的 - 並且你可以讓集合成爲另一個成員。很容易想象has_one訪問器返回非零「我不在這裏」的價值,這將使您的場景,但會有其他問題(主要是這樣的價值不會是假的,導致可以說rubiesque代碼較少)

+2

user.build_profile(given_name:「Michael」,姓:「Colin」)就是答案。獎金,網站鏈接guides.rubyonrails.org是一個獎金正是我所期待的。書籍和在線教程不足以提供這些信息。 – smileyUser

+0

這是由guide.rubyonrails提供的一個很好的參考,我經常發現自己回到了一次又一次 – pruett

相關問題