2015-04-22 91 views
1

我试图保存我的模型对象导轨时出现错误。让我说,我没有使用数据库迁移,并使用预先存在的数据库与轨道。 这里是我的模型类:Rails的ActiveRecord保存错误未定义的方法'[]'为零:NilClass

require 'bcrypt' 
require 'securerandom' 
class Profile < ActiveRecord::Base 
    include BCrypt 

    self.table_name = 'profiles' 
    self.primary_key = 'id' 

    attr_accessor :id, :username, :password_hash, :salt, :first_name, :last_name, :location, :status, :game_status 

    def initialize(attributes = {}, options = {}) 
    @username = attributes[:username] 
    @salt = SecureRandom.hex 
    @password_hash = Password.create(attributes[:password] + @salt).to_s 
    @first_name = attributes[first_name] 
    @last_name = attributes[last_name] 
    @location = attributes[location] 
    @status = "Hi" 
    @game_status = "Playing some game..." 
    end 

    def hash_rep 
    hash = {} 
    hash['id'] = @id 
    hash['username'] = @username 
    hash['password_hash'] = @password_hash 
    hash['salt'] = @salt 
    hash['location'] = @location 
    hash['status'] = @status 
    hash['game_status'] = @game_status 
    return hash 
    end 

end 

这里是我的数据库架构:

id    int Unsigned NOT NULL AUTO_INCREMENT 
username  varchar(16) NOT NULL 
password_hash tinytext  NOT NULL 
salt   varchar(64) NOT NULL 
first_name  varchar(16) NOT NULL 
last_name  varchar(16) NOT NULL 
location  tinytext  NOT NULL 
status   tinytext  NULL 
game_status tinytext  NULL 

这是我为我的控制器代码:

def register 
    profile = Profile.new(:id => params[:id], 
          :username => params[:username], 
          :password => params[:password], 
          :first_name => params[:first_name], 
          :last_name => params[:last_name], 
          :location => params[:location]) 
    profile.save 
    render_profile(profile) 
    end 

上的个人资料时发生错误。保存'方法。下面是相关堆栈跟踪:

activerecord (4.2.0) lib/active_record/transactions.rb:375:in `clear_transaction_record_state' 
activerecord (4.2.0) lib/active_record/transactions.rb:306:in `ensure in rollback_active_record_state!' 
activerecord (4.2.0) lib/active_record/transactions.rb:306:in `rollback_active_record_state!' 
activerecord (4.2.0) lib/active_record/transactions.rb:285:in `save' 
app/controllers/profile_controller.rb:52:in `register' 
actionpack (4.2.0) lib/action_controller/metal/implicit_render.rb:4:in `send_action' 
actionpack (4.2.0) lib/abstract_controller/base.rb:198:in `process_action' 

错误说:“未定义的方法`[]”为无:NilClass”

+1

有一个名为'params'在'register'没有局部变量。也就是说,局部变量'params'在第一次出现时被初始化为'nil'; 'params [:id]'在此相当于'nil [:id]'导致你得到的错误。 – mudasobwa

+0

在控制台中逐步完成此操作:通过从日志中复制设置参数并逐行执行代码。你应该能够看到什么是不对的。 –

+3

哎哟,你做了很多错误的东西:当它关于表列时,不需要attr_accessors,不要重新初始化 – apneadiving

回答

1
require 'bcrypt' 
require 'securerandom' 
class Profile < ActiveRecord::Base 
    include BCrypt 

    self.table_name = 'profiles' 
    self.primary_key = 'id' 

    def hash_rep 
    hash = {} 
    hash['id'] = id 
    hash['username'] = username 
    hash['password_hash'] = password_hash 
    hash['salt'] = salt 
    hash['location'] = location 
    hash['status'] = status 
    hash['game_status'] = game_status 
    hash 
    end 

    def self.build(args) 
    new_profile = Profile.new 
    new_profile.username = args[:username] 
    salt = SecureRandom.hex 
    new_profile.password_hash = Password.create(args[:password] + salt).to_s 
    new_profile.first_name = args[:first_name] 
    new_profile.last_name = args[:last_name] 
    new_profile.location = args[:location] 
    new_profile.status = "Hi" 
    new_profile.game_status = "Playing some game..." 
    new_profile 
    end 
end 

现在你可以使用它像:

Profile.build({ username: 'foo' }) 

顺便说一句,你hash_rep方法是没有多大用处的,请尝试:

profile = Profile.build({ username: 'foo' }) 
profile.attributes 

图片的标题说明:

  • 自你遵循约定,你不需要添加th OSE线,你可以删除它们:self.table_name = 'profiles'self.primary_key = 'id'

  • 提防哈希,似乎你不约字符串或符号键照顾,但他们是不一样的

  • 有写更优雅的方式是你的方法,但我已经把它简单,因为它没有必要在这个阶段

+0

感谢这对我有用。 –

0

在新的方法中,你应该改变这些是符号,从:

@first_name = attributes[first_name] 
@last_name = attributes[last_name] 
@location = attributes[location] 

要:

@first_name = attributes[:first_name] 
@last_name = attributes[:last_name] 
@location = attributes[:location] 

而且,你不必在一个选项哈希通过?因为你不使用它。

0

一个更好的方法来设置轨道默认属性来阐述是通过回调:

require 'bcrypt' 
require 'securerandom' 
class Profile < ActiveRecord::Base 
    include BCrypt 

    attr_accessor :password # is a virtual attribute 

    after_initialize do 
    if new_record? 
     # values will be available for new record forms. 
     self.status = status || "Hi" 
     self.game_status = game_status || "Playing some game..." 
    end 
    end 

    before_validation(on: :create) do 
    self.salt = SecureRandom.hex 
    self.password_hash = Password.create(password + salt).to_s 
    end 

    # Yuck. use http://apidock.com/rails/ActiveModel/Serialization/serializable_hash 
    def hash_rep 
    serializable_hash(only: [:id, :username, :password_hash, :salt, :location, :status, :game_status]) 
    end 

end 

您不需要为ActiveRecord列创建访问器。您无需指定tableprimary_key。 Rails指出了你。另外你真的不想重新定义initialize,因为活跃的记录在那里有一堆。

您的控制器也缺少标记。 Rails通常在资源名称下嵌套参数。 - 如果您使用Rails 4,你会whitelist和分配参数:

class ProfileController < ApplicationController 

    def new 
    @profile = Profile.new 
    end 

    def register 
    @profile = Profile.new(create_params) 
    if @profile.save 
     redirect_to @profile 
    else 
     render action: :new 
    end 
    end 

    private 
    def create_params 
    params.require(:profile).allow(:username, :password, : first_name :last_name :location) 
    end 
end 
+0

我不同意,回调是瘟疫。如果您在构建某些东西时需要默认值,那么您只需使用构建器。它是众所周知和使用的设计模式的一部分 – apneadiving

+0

有大量的样板分配代码悬而未决听起来像是一个非常好的主意 - 不是。 – max

+0

的确,有更好的方法,但你正在回答初学者。所以现在不需要混淆他。顺便说一句,他coulnt使用你的代码没有得到一个例外:'密码不是一个属性' – apneadiving

相关问题