2015-04-22 141 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

相關問題