🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 5

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

Q&A

3回答

2358閲覧

rails ポイントの平均を出すところでundefined method `to_i' for のエラーがでます

tori315

総合スコア21

Ruby on Rails 5

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

0グッド

2クリップ

投稿2019/12/26 10:30

初学者です。入力画面で、相手への評価ポイントを入れて、今までのポイントと合わせて平均を求めるところで、
undefined method `to_i' for <ActionController::Parameters {"point"=>"5"} permitted: true>:ActionController::Parameters Did you mean? to_h to_s
というエラーが出ています。
どう直したらいいのか分かりません。すいませんが、お知恵を貸してください。

html

1<%= form_tag("/posts/#{@post.id}/finishedafter",method: :post) do %> 2 <p>タイトル</p> 3 <h3><%=@post.title%></h3> 4 <p>取引相手</p> 5 <h3><%=@post.postedname%></h3> 6 <p>評価0~5(最高は5です)</p> 7 <div class="select"> 8 <select name="point" id="point" required > 9 <option selected value= "" >選択してください</option> 10 <option value= "0" >0</option> 11 <option value= "1" >1</option> 12 <option value= "2" >2</option> 13 <option value= "3" >3</option> 14 <option value= "4" >4</option> 15 <option value= "5" >5</option> 16 </select> 17 </div> 18 <div class="new-btn"> 19 <label><input class="btn btn-danger btn-lg " type="submit" value="取引を完了する"></label> 20 </div> 21 <% end %>

という形で送り。

ruby

1 2post.controller 3 4def finishedafter 5 newpoint = params.permit(:point) 6 @post = Post.find_by(id:params[:id])   <=相手の投稿 7 @user = User.find_by(id:@post.user_id)  <=相手のデータ 8 9 @user.finishcount += 1           <=平均を求めるための件数 10 @user.point.to_f = (@user.point + newpoint.to_i) / @user.finishcount  11  (相手の評価ポイント = 相手のポイント + 今回のポイント / 件数) 12 @user.save 13 redirect_to("/") 14 end

db

1 2create_table "users", force: :cascade do |t| 3 t.string "user_name" 4 t.string "password_digest" 5 t.string "email" 6 t.datetime "created_at", null: false 7 t.datetime "updated_at", null: false 8 t.string "imagename" 9 t.integer "point" 10 t.boolean "admin", default: false 11 t.integer "finishcount" 12 end

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

変数にどんな値(どのclassのインスタンス)が入っているのか、を意識するようにしてください。変数名から期待されるものが入るわけではないです。
newpoint = params.permit(:point) で newpoint には ポイントは入っていません {point: 5} というActionController::Parametersが入っています、
5を得るには newpoint = params[:point].to_fにしてください。
それで @user.point = (@user.point + newpoint.to_i) / @user.finishcount はエラーはでなくなります。

ただ、この式では 平均値はでません。
4つの評価の平均値が 3 で今回新たに 評価5が来るとこの式では(3+5)/5 で1.6になってしまいます。(3*4+5)/5で3.4が正しい新しい平均値です

投稿2019/12/27 08:39

winterboum

総合スコア23567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tori315

2019/12/27 12:38

ありがとうございます。エラーは出なくなったのですが、 def finishedafter @newpoint = params[:point].to_f @post = Post.find_by(id: params[:id]) @user = User.find_by(id: @post.user_id)   @pp = (@user.point.to_f * @user.finishcount) + @newpoint @user.finishcount += 1 @user.point = @pp.round(2) / @user.finishcount @user.save @post.switch = 2 @post.save redirect_to("/") end @user = User.find_by(id: @post.user_id)の部分でユーザーが呼び出されず、dbのuserの内容が変わらないのですが、なぜ呼び出されないのか分かりません。(postの方はデータが反映されます)どのようなことが原因として考えられるのでしょうか。 dbのpostsテーブルには、t.integer "user_id"のカラムはあります。
winterboum

2019/12/27 13:20

カラムは有っても値が入っていないのでは?
tori315

2019/12/27 14:07

user_idには、userテーブルのuser.idと同じ数値が入っているのですが、なぜか @user = User.find_by(id: @post.user_id)が働いていないようなのです。。
winterboum

2019/12/30 07:13

寝落ちしてしまって、コメントあるのに今気が付きました。 しかし @userが取れない? 面妖な、、、 いや、違うな @user = User.find_by(id: @post.user_id) に失敗すると @user には nil がはいります。 そうすると @user.point、 @user.finishcount、@user.saveで、Nill class にはそんなmethodはない エラーで落ちます。 落ちては居ないようですがから、読めてます。 すると、@user.saveの失敗だな。 rails c で同じ操作をおこなって、 @user.save が成功しているかどうか見てください。 @user.errors.full_messages を見ると失敗の原因がわかります
tori315

2019/12/30 12:59

ありがとうございます。 すいません、これでやり方が正しいのか分からないのですが、consoleでやってみたら、@user.saveで falseが出ました。 irb(main):006:0> @user = User.find_by(id: 50) User Load (10.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 50], ["LIMIT", 1]] => #<User id: 50, user_name: "田中", password_digest: "$2a$12$hklWHscxLXb1BQwyIn9XhOBIbGsRDR1ibII6G1KgEDp...", email: "ss@ss", created_at: "2019-12-27 13:57:28", updated_at: "2019-12-27 13:57:28", imagename: "default_user.jpg", admin: false, finishcount: 0, point: 0.0> irb(main):007:0> @pp = (@user.point.to_f * @user.finishcount)+4 => 4.0 irb(main):008:0> @user.finishcount += 1 => 1 irb(main):009:0> @user.point = @pp.round(2) / @user.finishcount => 4.0 irb(main):010:0> @user.save (0.1ms) begin transaction User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = ? AND "users"."id" != ? LIMIT ? [["email", "ss@ss"], ["id", 50], ["LIMIT", 1]] (0.1ms) rollback transaction => false irb(main):011:0> @user.errors.full_messages を見ると失敗の原因がわかります。←これはどのようにしたらいいのでしょうか。
winterboum

2019/12/30 14:49

@user.save でエラーになったところで @user.errors.full_messages としてください その結果と共に、model Userの定義も載せてください
tori315

2019/12/30 15:07

これでいいのでしょか?よろしくお願いします。 irb(main):011:0> @user.errors.full_messages => ["Passwordを入力してください", "Passwordは6文字以上で入力してください"] class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable validates :email,{uniqueness:true,presence:true} validates :user_name,{presence: true} validates :user_name,length:{maximum: 40} validates :password,{presence: true} validates :password,length:{minimum: 6} validates :password,length:{maximum: 18} #has_many :posts => :delete has_many :posts, dependent: :destroy has_many :accepts, dependent: :destroy has_secure_password has_many :messages, dependent: :destroy has_many :entries, dependent: :destroy def self.search(search) if search User.where(['user_name LIKE?',"%#{search}%"]) else User.all end end end
winterboum

2019/12/30 22:12

それで、Userがsaveされない原因が出ていますが、わかりますか
tori315

2019/12/31 05:14

パスワードが必要ということで、 @user.update(user_params) を @user.saveの前に入れて、 def user_params params.permit(:user_name,:email,:password) end をpostコントローラにつくり、 viewで <input type="hidden" name="user_name" value="<%=@user.user_name%>"> <input type="hidden" name="email" value="<%=@user.email%>"> <input type="hidden" name="password" value="<%= @user.password %>"> を入れて、パスワードが送れるようにしようとしましたが、ダメでした。 すいません。わかりません。
winterboum

2019/12/31 05:37

おしい。 パスワードを必須とするのはloginとユーザ登録の場合で、それ以外ではパスワードを要求するのはおかしいですよね。 ですので、validationに手を入れましょう passwordのvalidation3つ全てに if: :present? を追加してください。
tori315

2019/12/31 11:07

そういうことだったんですか。validationが効いたままなんですが、以下の書き方が違うのか他の原因があるのでしょうか。 validates :password,presence: true,if: :present? validates :password,length:{maximum: 18},if: :present? validates :password,length:{minimum: 6},if: :present?
winterboum

2019/12/31 11:54

if: Proc.new { |a| a.password.present? } に変えてみてください
tori315

2020/01/01 04:28

ちょっとトラブルで、だいぶ先に戻ってしまいました。。 すいません。またちょっと作り直していきます。
tori315

2020/01/02 09:13

上記のやり方で解決しました。 助かりました。今年もまたお力を貸してください。 ありがとうございました。
guest

0

まず仕様を確認したいです
想像するに、post.pointにいろんな人がその企業を評価した平均値が入るというものだと思うのですが
これは整数でいいのですか?小数点以下は不要ですか?
小数点以下も必要ならpointがinteger型になっている点がおかしいです

つぎにpostが作られるところのコードを張ってください
Post.newでpostデータが作られたときにちゃんと、pointの初期値が入ってますか?
入っていなければ、nilになるので注意してください

投稿2019/12/26 22:49

story_aniki

総合スコア197

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tori315

2019/12/27 01:00

そうですね。integerはfloatにデータ型を変えました。 pointはuserで作りました。 def new @user = User.new end def create @user = User.new(user_params) @user.imagename = "default_user.jpg" @user.point = 0 @user.finishcount = 0 @user.save if @user.save session[:user_id] = @user.id flash[:notice] = "登録に成功しました" redirect_to("/users/#{@user.id}") #show else if User.find_by(email:params[:email]) @error_message = "そのEmailアドレスは使われています" else @error_message = "パスワードは6~18字です" end render("/users/new") end end エラーの内容が、 undefined method `to_f' for <ActionController::Parameters {"point"=>"5"} permitted: true>:ActionController::Parameters Did you mean? to_h to_s なのですが、 @user.point = (@user.point.to_f + newpoint.to_f) / @user.finishcount を、 @user.point = (@user.point + newpoint / @user.finishcount に変えると、 ActionController::Parameters can't be coerced into Integer とでます。
guest

0

@user.point.to_f = (@user.point + newpoint.to_i) / @user.finishcount 

この部分を

@user.point= (@user.point.to_f + newpoint.to_f) / @user.finishcount 

としてみるとどうなりますか?

投稿2019/12/26 11:05

story_aniki

総合スコア197

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tori315

2019/12/26 11:14

回答ありがとうございます。 そうしたら、コントローラのところの、 @user.finishcount += 1; の部分で、 undefined method `+' for nil:NilClassというエラーがでてしまいました。
story_aniki

2019/12/26 11:40

おそらく、user.finishcount がnilだったのでしょう。Rubyではnilもオブジェクトなので、演算を含め存在しないメソッドを呼ぼうとすればNoMethodErrorになります 事前にnilの場合を弾いておく、あるいはnilなら適当な値を代入するなどしてください
tori315

2019/12/26 13:26

そこは、クリアできたのですが、やはり @user.point= (@user.point.to_f + newpoint.to_f) / @user.finishcount の部分で undefined method `to_f' for <ActionController::Parameters {"point"=>"5"} permitted: true>:ActionController::Parameters Did you mean? to_h to_s というエラーがでてしまいます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問