我有几周的经验或接近一个月学习Ruby on Rails。我希望理解为什么我不能通过相关对象获取方法。
我正在尝试获取附加到用户的关联对象,而不是单独使用stane的Profile.new,例如简介及其方法如下所示。
user.profile.create
user.profile.create!
user.profile.build
而是我得到RSpec错误消息。 NoMethodError:nil的未定义方法`build':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+\-.]+@[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
smileymike@ubuntu:~/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
答案 0 :(得分:3)
has_one会在用户上为您提供build_profile方法。有关详细信息,请参阅http://guides.rubyonrails.org/association_basics.html#has_one-association-reference。
你不能做user.profile.build的原因是没有配置文件,所以user.build返回nil,并且要求nil构建配置文件是没有意义的。这与has_many情况不同,其中out总是返回一组事物 - 即使集合是空的 - 并且您可以要求集合创建另一个成员。很容易想象has_one访问器返回一个非零的“我不在这里”的值,这将启用你的场景,但会有其他问题(主要是这样的值不会是假的,导致可以说是更少的rubyesque代码)