7

だから私はログイン、メールアドレス、パスワード、パスワード確認、名前、アバター(写真)などのユーザーモデルを持っています。最初の5つには検証があり、基本的に5つすべてが存在する必要があると述べています。新しいモデル。

ただし、これにより、更新に関する問題が発生します。

ユーザーが自分の名前とアバターのみを編集できる編集ページがあります。現在、ログインを変更させるつもりはありません。別のページからメールアドレスとパスワードを変更したいと思います。

したがって、編集フォームは次のようになります。

<% form_for @user, :html => { :multipart => true } do |u| %>
 <p>
  <label>Name:</label>
  <%= u.text_field :name %>
 </p>
 <p>
  <label>Avatar:</label>
  <%= display_user_avatar %>
  <%= u.file_field :avatar%>
 </p>
 <p>
  <%= submit_tag %>
 </p>
<% end %>

を実行しようとすると、@user.update_attributes(params[:user])パラメータが2つしかないため、更新は失敗します。これは、エントリの検証にパスワード、パスワード確認、電子メールなどが必要であり、それらがそのフォームに存在しないためです。nameavatar

を実行することでこれを回避できます@user.update_attribute(:name, params[:user][:name])が、検証を回避することがGoodThing™であるかどうかが心配です。特にパスワードの更新のようなものに関しては、新しいパスワードを検証する必要があります

別の方法はありますか?

そして、単にupdate_attribute forとを使用してこれ行うとしたら、どうすればよいでしょうか。:name:avatar

これは機能しますか?

params[:user].each do |attribute|
  @user.update_attribute(attribute, params[:user][attribute])
end

これはこれを行うための許容できる方法ですか...?


--フォローアップとして編集--Okie
、私はあなたが提案したように試しました

  def update
    @user = User.find_by_login(params[:id])
    if @user.update_attributes!(params[:user])
      redirect_to edit_user_path(@user)
    else
      flash[:notice] = @user.errors
      redirect_to edit_user_path(@user)
    end
  end

つまり、!バージョンを実行していて、ブラウザにキャッチされて表示される例外は次のとおりです。

Validation failed: Password is too short (minimum is 5 characters)

サーバーログの情報は次のとおりです。

Processing UsersController#update (for 127.0.0.1 at 2010-07-18 11:56:59) [PUT]
  Parameters: {"user"=>{"name"=>"testeeeeee"}, "commit"=>"Save changes", "action"=>"update", "_method"=>"put", "authenticity_token"=>"BMEGRW/pmIJVs1zlVH2TtZX2TQW8soeCXmMx4kquzMA=", "id"=>"tester", "controller"=>"users"}

うーん。これを見て、提出していることに気づきました"id"=>"tester"。これで、user_idではなくユーザーのログイン名が表示されるようにルートを設定しました...それが理由でしょうか?でユーザーの更新を見つけようとしていますuser_id == testerが、存在しないため、代わりに作成しようとしていますか?それは実際に私がルートのために間違っていることですか?

うーん...レーキルートは、ルートが次のとおりであることを教えてくれます:

edit_user GET    /users/:id/edit(.:format)                             {:action=>"edit", :controller=>"users"}
          PUT    /users/:id(.:format)                                  {:action=>"update", :controller=>"users"}

user.rbそして、私はファイルにそのようなルートを設定しました:

  def to_param
    "#{login}"
  end

しかし、それはこの間ずっとloginではなく、間違いなく表示されています。idしかし、私はまた、更新アクションの最初に、を実行してから@user = User.find_by_login(params[:id])、それを更新してい@userます。

私はとても混乱しています。>。<


2番目の更新:

私のUser.rb検証は次のとおりです。

  validates_length_of :login, :within => 3..20
  validates_length_of :password, :within => 5..20
  validates_presence_of :login, :email, :password, :password_confirmation, :salt, :name, :on => :create
  validates_uniqueness_of :login, :case_sensitive => false
  validates_confirmation_of :password
  validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :message => "format is invalid."
  attr_accessor :password, :password_confirmation

そして、hashed_pa​​sswordセクションはここにあります:

  def password=(pass)
    @password = pass
    self.salt = User.random_string(10) if !self.salt?
    self.hashed_password = User.encrypt(@password, self.salt)
  end

u.attributes私にくれます

>> u.attributes
=> {"salt"=>"NHpH5glxsU", "name"=>"test er", "avatar_updated_at"=>nil, "updated_at"=>Sat Jul 17 07:04:24 UTC 2010, "avatar_file_size"=>nil, "avatar_file_name"=>nil, "hashed_password"=>"84f8675c1ed43ef7f8645a375ea9f867c9a25c83", "id"=>1, "avatar_content_type"=>nil, "login"=>"tester", "email"=>"tester@tester.com", "created_at"=>Fri May 07 10:09:37 UTC 2010}

うーん...わかりました。仮想属性passwordが実際には存在しないことについて、あなたが言ったことです...では、どうすればそれを回避できますか?バガー、ここで私は自分の認証コードを賢くいじっていると思った...

これらの認証プラグインの1つに変更するのは簡単ですか?新しいユーザーモデルを作成する必要がありますか?または、プラグインは現在のプラグインで動作できる必要がありますか?

これまでのすべての助けに感謝します、ところで!:D

4

1 に答える 1

10

私はこれを確認しましたが、2つの属性の部分的な更新は正常にupdate_attributes機能します。他のすべての属性は以前の値のままです。つまり、検証が失敗することはありません。試すべきことがいくつかあります:

  • コントローラアクションで、を介してユーザーをロードしていますUser.findか?つまり、有効なモデルから始めていますか。
  • 検証エラーが原因で更新が失敗していることを確認しますか?をに置き換えてみてupdate_attributesくださいupdate_attributes!。後者は、検証のために更新が失敗した場合に例外をスローします。または@user.errors、更新を試みた後、どの検証が失敗したかを確認してください。

アップデート

一致するレコードが見つからない場合User.find_by_loginは返さnilれ、新しいレコードは作成されません。データベース内のテスターユーザーのパスワードが短すぎる可能性はありますか?コードに検証を入れる前に、そのユーザーが作成されたのではないでしょうか。レコードを保存する前に、何らかのプラグインまたはコールバックを使用してユーザーパスワードを暗号化していますか?実際にはpassword保存されていない仮想属性であり、実際のパスワードは次のようなフィールドにありencrypted_passwordますか?

これを試してみてくださいscript/console(アプリをテストしているのと同じ環境を使用してください-開発または本番)

> user = User.find_by_login 'tester'
> user.valid?
> user.attributes

user.valid?に戻りtruefalse更新を試みる前に、ユーザーが最初から有効であるかどうかを通知します。

アップデート2(検証の修正)

User独自のコードを修正するという点では、モデルに次のようなメソッドを追加できます。

def password_validation_required?
  hashed_password.blank? || !@password.blank?
end

true次に、パスワードに関連するすべての検証ルールを更新して、このメソッドが次を返す場合にのみ適用されるようにします。

validates_length_of :password, :within => 5..20, 
  :if => :password_validation_required?

これが言っているのは、hashed_password(たとえば、新しいユーザーに対して)まだ(新しいユーザーに対して)持っていない場合、または新しいプレーンテキストのパスワードが。を介して指定されている場合にのみ、パスワード検証ルールを実行することですpassword=。ユーザーがすでにパスワードを持っていて、それが変更されないままになっている場合は、パスワードの検証をスキップしてください。

ただし、プラグインの使用を検討するのは正しいことです。独自の認証コードを作成することは興味深い演習になる可能性があり、異常な要件がある場合は必要になる可能性があります。欠点は、思いもよらなかったセキュリティの問題が発生する可能性があることです。restful_authenticationのようなものをアプリに後付けすることはそれほど悪くないはずです。モデルの1つまたは2つのフィールドの名前を変更する必要がある場合がありますUser

于 2010-07-17T16:04:03.327 に答える