質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.76%

  • Ruby on Rails

    6743questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

railsのform_forをモデルの一部の要素だけ作成したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 276

sakas1231

score 23

今、Ruby on Railsで、Userモデルに:name, :email, :password, :password_confirmation, :budgetの5つが入っています。

これら五つのうち、nameとemailとbudgetのみのテキストフィールドを表示させるページ( user/:id/edit )を作成して、form_forでupdateさせたいと思っています。( 残りのpasswordとpassword_confirmationはこのページでは変更を加えないということです )

そこで、以下のようなform_forを作り、controllerのupdateアクションにいかせようと思ったのですが、どうも正常にupdateされません。( updateのflash[:notice]側のelseにいってしまう )

原因はedit.html.erb内でpasswordとpassword_confirmationについて明示していないのでuser_paramsの値が

"user"=>{"name"=>"after_hoge", "email"=>"afterhoge@example.com", "budget"=>"10000"}

になってしまっているということがわかったのですが、それに対する対処法がわからないです。

どなたかご教授願えますでしょうか?

edit.html.erb

<div class="well col-md-6 col-md-offset-3">
      <!--small>初めての方はアカウントを<%= link_to "新規作成", signup_path %>してください</small-->

      <%= form_for(@user) do |form| %>
        <div class="field">
          <%= form.label :name %>
          <%= form.text_field :name, id: :user_name, class: 'form-control'%>
        </div>

        <div class="field">
          <%= form.label :email %>
          <%= form.text_field :email, id: :user_email, class: 'form-control' %>
        </div>

        <div class="field">
          <%= form.label :budget ,'今月の予算' %>
          <%= form.number_field :budget, id: :user_budget, class: 'form-control' %>
        </div>



        <!--div class="field">
          <%= form.label :exp %>
          <%= form.number_field :exp, id: :user_exp %>
        </div>

        <div class="field">
          <%= form.label :level %>
          <%= form.number_field :level, id: :user_level %>
        </div-->

        <div class="actions text-center"><br>
          <%= form.submit '登録', class: 'btn btn-primary' %>
        </div>
      <% end %>

updateアクション

 def update
    respond_to do |format|
      if @user.update(user_params)
          flash[:success] = "User was successfully updated."
          format.html { redirect_to @user }
          format.json { render :show, status: :ok, location: @user }
          return redirect_to user_url @user
      else
          #puts(user_params)
          flash[:notice] = "User updating was failed."
          format.html { render :edit }
          format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end

[修正内容]
モデル側のバリデーションとのことで、user.rbとuser_test.rbを載せさせていただきます。
ちなみにreils testは通ってます(全然テスト書いていないのであたりまえかもしれないですが)
user.rb

class User < ApplicationRecord
    has_many :books, dependent: :destroy
    before_save { self.email = email.downcase }
      validates :name,  presence: true, length: { maximum: 50 }
      VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
      validates :email, presence: true, length: { maximum: 255 },
                        format: { with: VALID_EMAIL_REGEX },
                        uniqueness: { case_sensitive: false }
      validates :budget, numericality: true
      validates :password, presence: true, length: { minimum: 6 }
      has_secure_password

      # 与えられた文字列のハッシュ値を返す
      def User.digest(string)
        cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                      BCrypt::Engine.cost
        BCrypt::Password.create(string, cost: cost)
      end

      # ランダムなトークンを返す
      def User.new_token
        SecureRandom.urlsafe_base64
      end
end

user_test.rb

require 'test_helper'

class UserTest < ActiveSupport::TestCase
  # test "the truth" do
  #   assert true
  # end
  #@user.validはバリデーションを通るとture,invalidだと逆に通らないとtureになる

  def setup
    @user = User.new(name: 'foobar', email: 'sample@example.com', budget: 1000, exp:0, level:0, password:'foobar', password_confirmation: 'foobar')
  end

  #正しいユーザーはバリデーションを通る
  test "user validates all" do
    assert @user.valid?
  end

  #名前が50文字以上だと通らない
  test "user validates name" do
    @user.name = "a" * 51
    assert @user.invalid?
  end

  #emailは正しいものを
  test "user validates email" do
    @user.email = "a"
    assert @user.invalid?
  end

  #budgetは整数で
  test "user validates budget" do
    @user.budget = "100a"
    assert @user.invalid?
  end

  #passwordは6文字以上
  test "user validates password" do
    @user.password = "a" * 5
    @user.password_confirmation = @user.password
    assert @user.invalid?
  end

  #passwodとpassword_confirmationは同じでなくてはいけない
  test "user validates passowrd = password_confirmation" do
    @user.password = "difference"
    assert @user.invalid?
  end

  #登録されているemailは使えない(user.ymlのoneがtest@sample.com)
  test "user validates email exists" do
    @user.email = "test@sample.com"
    assert @user.invalid?
  end
end
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kenchankunsan

    2017/10/21 19:18

    else句の中で、putsやRails.logger等を使って @user.errorsの中身を表示されると何か入っていますか?

    キャンセル

  • sakas1231

    2017/10/24 16:20

    返信遅くなってしまい申し訳有りません。 @user.loggerには何も入っていませんでした... password以外のformをhiddenにするのはできるのですが、passwordだけhiddenにすることができない感じです

    キャンセル

  • sakas1231

    2017/10/24 16:22

    putsを使ってeditアクションからupdateを通してshowに戻る時に、showアクションの段階で@user.passwordにnullが入っている状態でした。 passwordはdbにハッシュにされて保存されているのでhiddenで直接@user.passwordを代入することはできないということでしょうか?

    キャンセル

回答 1

checkベストアンサー

0

公開してもらったコードの以下のputs(user_params)の出力が以下のようになっているということでしょうか?

"user"=>{"name"=>"after_hoge", "email"=>"afterhoge@example.com", "budget"=>"10000"}

 def update
    respond_to do |format|
      if @user.update(user_params)
          flash[:success] = "User was successfully updated."
          format.html { redirect_to @user }
          format.json { render :show, status: :ok, location: @user }
          return redirect_to user_url @user
      else
          #puts(user_params) # ここの出力
          flash[:notice] = "User updating was failed."
          format.html { render :edit }
          format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end

もしそうなのであれば、updateの引数に渡すべきは以下のような形のhashになるので、

{"name"=>"after_hoge", "email"=>"afterhoge@example.com", "budget"=>"10000"}

updateに渡す部分を以下のように書くと更新できるのではないでしょうか?

@user.update(user_params[:user])

質問への追記にあった「passwordが空になっているからではないか?」というのは、ハッシュのキー自体が無い場合は何も更新が行われないので、問題無いかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.76%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby on Rails

    6743questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。