15

モデルにデータベースとの関係を持たせたくないので、モデルにActiveRecordの代わりにActiveModelを使用しようとしています。

以下は私のモデルです:

class User
  include ActiveModel::Validations
  validates :name, :presence => true
  validates :email, :presence => true
  validates :password, :presence => true, :confirmation => true

  attr_accessor :name, :email, :password, :salt
  def initialize(attributes = {})
    @name  = attributes[:name]
    @email = attributes[:email]
    @password = attributes[:password]
    @password_confirmation = attributes[:password_confirmation]
  end
end

そして、これが私のコントローラーです:

class UsersController < ApplicationController
  def new
    @user = User.new
    @title = "Sign up"
  end
end

そして私の見解は:

<h1>Sign up</h1>

<%= form_for(@user) do |f| %>
<div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
</div>
<div class="field">
    <%= f.label :email %><br />
    <%= f.text_field :email %>
</div>
<div class="field">
    <%= f.label :password %><br />
    <%= f.password_field :password %>
</div>
<div class="field">
    <%= f.label :password_confirmation, "Confirmation" %><br />
    <%= f.password_field :password_confirmation %>
</div>
<div class="actions">
    <%= f.submit "Sign up" %>
</div>
<% end %>

しかし、このビューをブラウザにロードすると、例外が発生します。

undefined method 'to_key' for User:0x104ca1b60

誰かがこれを手伝ってくれませんか?

よろしくお願いします!

4

2 に答える 2

33

Rails 3.1のソースを探し回ってこれを整理しましたが、他の場所を検索するよりも簡単だと思いました。Railsの以前のバージョンも同様である必要があります。tl; drの場合、最後にジャンプします。


あなたが電話するときform_for(@user)、あなたはこれを通過するのをやめます:

def form_for(record, options = {}, &proc)
  #...
  case record
  when String, Symbol
    object_name = record
    object      = nil
  else
    object      = record.is_a?(Array) ? record.last : record
    object_name = options[:as] || ActiveModel::Naming.param_key(object)
    apply_form_for_options!(record, options)
  end

また、@userは文字列でもオブジェクトでもないため、elseブランチを通過して。に移動しapply_form_for_options!ます。内部apply_form_for_options!にはこれがあります:

as = options[:as]
#...
options[:html].reverse_merge!(
  :class  => as ? "#{as}_#{action}" : dom_class(object, action),
  :id     => as ? "#{as}_#{action}" : dom_id(object, action),
  :method => method
)

コードのそのチャンクに注意してください。問題の原因と解決策の両方が含まれています。次のようなdom_idメソッド呼び出し:record_key_for_dom_id

def record_key_for_dom_id(record)
  record = record.to_model if record.respond_to?(:to_model)
  key = record.to_key
  key ? sanitize_dom_id(key.join('_')) : key
end

そして、へのあなたの呼び出しがありますto_keyto_keyメソッドはによって定義され、ActiveRecord::AttributeMethods::PrimaryKeyActiveRecordを使用していないため、to_keyメソッドはありません。モデルに主キーのように動作するものがある場合は、独自のキーを定義to_keyしてそのままにしておくことができます。

しかし、戻ってみると、apply_form_for_options!別の解決策があります。

as = options[:as]

したがって、フォームのDOMIDを手動で生成する:asオプションを提供できます。form_for

<%= form_for(@user, :as => 'user_form') do |f| %>

:asただし、値がページ内で一意であることを確認する必要があります。


エグゼクティブサマリー

  • モデルに主キーのように動作する属性がある場合は、それto_keyを返す独自のメソッドを定義します。
  • または、に適切な:asオプションを指定しform_forます。
于 2011-07-17T05:45:42.107 に答える
1

代わりに(あまり文書化されていない)ActiveModel::Conversionsクラスを調査する必要があるようです

https://github.com/rails/rails/blob/3-1-stable/activemodel/lib/active_model/conversion.rb

  include ActiveModel::Conversion

  def persisted?
    false
  end

Rails4.2にも同じことが当てはまります。

于 2016-06-14T21:49:06.120 に答える