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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

Ruby on Rails

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

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

Q&A

解決済

4回答

7434閲覧

controller内のif文でどのメソッドを使えば良いか

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

Ruby on Rails

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

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

0グッド

0クリップ

投稿2015/10/08 13:02

編集2015/10/13 13:03

###実現したいこと
indexにてx枚の画像から、ランダムで2枚のみ抽出し表示させました。
クリックした画像の"score"カラムの数値を+=1させ、
クリックしなかった画像の"score"カラムの数値を-=1させたいです。
###発生している問題
クリックした方に+=1をさせることは出来ましたが、
クリックしなかった方に-=1をすることが出来ません。
おそらくif文を使えば良いとは分かるのですが、どのメソッドを使えば良いのか困っています。

###ソースコード

schema.rb create_table "photoposts", force: :cascade do |t| t.string "photo", limit: 255 t.string "caption", limit: 255 t.integer "score", limit: 4, default: 1500 t.integer "user_id", limit: 4 t.datetime "created_at" t.datetime "updated_at" end
routes.rb root to: 'photoposts#index' match '/', to: 'photoposts#vote', via: 'patch'
index.html.erb <% @photoposts.each do |photopost| %> <%= link_to image_tag(photopost.photo_url), root_path(:id => photopost.id), :method => "patch" %> <% end %>
photoposts_controller.rb def vote @photopost = Photopost.find(params[:id]) @photopost.score += 1 @photopost.save redirect_to root_url end

ご教授のほど宜しくお願い致します。

###追記

##修正 10/13 photoposts_controller.rb def index @photoposts = Photopost.find(Photopost.pluck(:id).shuffle[0..1]) end def vote @temp = params[:id] logger.debug(@temp) logger.debug(@target1) logger.debug(@target2) @target1 = Photopost.find(session[:target1]) ##Couldn't find Photopost with 'id'= @target2 = Photopost.find(session[:target2]) if session[:target1] == params[:id] @target1.score += 1 @target1.save @target2.score -= 1 @target2.save redirect_to root_url elsif session[:target2] == params[:id] @target1.score -= 1 @target1.save @target2.score += 1 @target2.save redirect_to root_url end end
<% count = 1, @photoposts.each do |photopost| %> <%= link_to image_tag(photopost.photo_url), root_path(:id => photopost.id), :method => "patch" %> <% session[('target'+count.to_s).to_sym]=photopost.id count=2 end%>

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

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

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

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

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

guest

回答4

0

ベストアンサー

いい心がけですね。

'''
<% count = 1, @photoposts.each do |photopost| %>
<%= link_to image_tag(photopost.photo_url), root_path(:id => photopost.id), :method => "patch" %>
<%
session[('target'+count.to_s).to_sym]=photopost.id
count=2
end%>
'''

'''
<% count = 1 @photoposts.each do |photopost| %>
<%= link_to image_tag(photopost.photo_url), root_path(:id => photopost.id), :method => "patch" %>
<%
session[('target'+count.to_s).to_sym]=photopost.id
count=2
end%>
'''
にしてみてください。
countの後に要らないカンマが入っています。これで直らなければ以下の方法で実装してください。(これが正攻法です。)

indexコントローラーが使えることが分かったので、絶対出来るやり方としては,indexコントローラーで@target1と@target2に選出された二枚の画像のidを代入し

root_pathの部分を

root_path(:id => photopost.id,:target1 => @target1,:target2 =>@target2)

とすれば絶対出来ます。乱数で選ばれた画像のidは乱数で決める時に保持するか,ループを回して保存してください。

投稿2015/10/13 13:14

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2015/10/13 14:04 編集

迅速なご対応ありがとうございます。 count = 1にするとSyntaxErrorが発生してしまいます。 なのでずっとcount = 1,とカンマを入れていました。 正攻法であるsessionを使わず、indexコントローラーをいじる方で実装してみようと思います。 難しそうではありますが、試行錯誤を繰り返してみようと思います。 長い間お付き合いさせてしまい申し訳ございませんでした。。。
退会済みユーザー

退会済みユーザー

2015/10/13 16:19 編集

ごめんなさい。忘れてたのですがrubyは改行入れないと式の続きと見なされてしまうらしいので,の所に空白でなく改行をいれてみてください。 syntaxerrorは改行いれないことによりよく起こるエラーらしいです。 rubyいじったの3年前くらいなので色々忘れてます。 こちらも試せる環境がないので動くコードを提示出来ず申し訳ないです。 理屈的には今の書き方でも確実に出来るはずで文法が間違ってるとこを直せば出来るはずだと思っています。 根拠はそもそもindexの%%で囲まれている中身は結局rubyのコードを書いてるのでコントローラーに引数を渡せるのであればコントローラーで書こうがビューで書こうが(保守のしやすさを除いて)対して差がないからです。MVCでは動的なDOM操作を除きコントローラーでデータのやりとりを完結させることが可能でそうあるように設計されています。なので本当の正攻法はindexコントローラー内でセッションを使うかインスタンス変数に保存したデータをパラメータを渡す方が正攻法です。 indexビューで書き直しましょうと言ったのはid決定部分が書いてなかったためid取得が出来るのがindexビュー内のみだと思っていて,文中から受け取ることも出来ることを知っていたので提示したのですが,分かりにくかったかもしれません。 試行錯誤するのは良いことです。どういう書き方が上手く行ってどういう書き方が悪いのか理解するためのステップになります。ここまで頑張ってもらっているので是非完成出来るといいですね。頑張ってください。今後も質問が目に止まったら答えるので基本的なことでも気兼ねなく質問していただければと思います。
退会済みユーザー

退会済みユーザー

2015/10/15 01:58 編集

コメントありがとうございます。 改行しても今度はif文が成立しなくなるので、 indexコントローラーにてインスタンス変数に保存→パラメータを渡すやり方にチャレンジしてみます。 非常に難しいとは思いますが、tkowさんの情報を参考にやってみます。 今回質問した事でRailsに対しての知識を深めていくことができ、 非常に満足しております。 今後また何かの縁があれば、その時はまたご教授願います!
guest

0

デバッグ用の参考にお使いください。

Railsでデバッグをする

投稿2015/10/11 21:05

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

コピペ用です。

photoposts_controller.rb def vote @target1 = Photopost.find(session[:target1]) @target2 = Photopost.find(session[:target2]) if session[:target1] == params[:id] @target1.score += 1 @target1.save @target2.score -= 1 @target2.save redirect_to root_url elsif session[:target2] == params[:id] @target1.score -= 1 @target1.save @target2.score += 1 @target2.save redirect_to root_url end end

<%session ~ end%> の部分を
<%
session[('target'+count.to_s).to_sym]=photopost.id
count+=1
end%>

投稿2015/10/11 14:25

編集2015/10/11 14:44
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2015/10/11 15:04

諦めかけていた所、再度回答ありがとうございます。 sessionについて自力で調べてみたものの、 ご指摘の通り全く理解出来ていない様なので、改めて詳しく勉強しようと思います。 詳しいcontrollerの書き方(コピぺまでも)、本当に助かります。 viewでのインクリメントについては、私もおかしいと思い修正していたのですが、 <% session[('target'+count.to_s).to_sym]=photopost.id count+=1 end%> に変えましたら、count += 1の'+'がエラーになる様になってしまいました。 これはcountを変数として扱うべきなのでしょうか?(またしても見当違いの場合すいません。。。)
退会済みユーザー

退会済みユーザー

2015/10/11 16:57 編集

rubyは昔少し触ったことあるくらいなのでうろ覚えなところが多くてすみません。 countと+の間と=と1の間にスペースを入れてみてもらえますか? それで治らなければ count =count+1 にしてみるとか半角が全角になっているのを疑うとかそういう可能性も考えてみてください おそらくこれで上手くいけばうまくいくと思いますよ。 あとエラーになんて書いてあるかもしわかれば教えてください。 追記:countはローカル変数として扱うべきです。ちなみに<% count=1 @post〜do〜%>の部分の宣言を忘れないようにしてください。が,それでもだめならcountを全て$countとしてグローバル変数になおしてください。何をしたいかというと,countで増やした数字とtargetという文字列を結合してsessionのキーにしてページが移動してもどの写真が選ばれたかというIDを保存しておくということがしたいということです。あとは最終手段はtarget1,2の汎用性を諦めて固定値にしてsession[:target1]にデータが入っているかどうかでif文で条件分岐する,本当に最終手段としてindexコントローラであらかじめ選出された二つのスコアを-1しておいて,選ばれたものを+2するとかくらいです。
退会済みユーザー

退会済みユーザー

2015/10/11 17:15

コメントありがとうございます。 提示して頂いた条件全てを試してみましたが、どれを試しても必ず count = count + 1の部分にundefined method `+' for nil:NilClassが発生します。。。
退会済みユーザー

退会済みユーザー

2015/10/11 18:36 編集

このエラーは変数未定義か変数に入っているデータが+演算子で計算できないものになっているときに出るエラーなんですよね。 <%~%>はrubyのコードそのまま使えるはずなので,おかしいですね。試しにcount+=1をcount=2にしてみてもらえるでしょうか。それでも正しく実行できなければ恐らく書き方が間違っている可能性があるのでindexファイルのeach分含む最初の%からendを含む末尾の%までの記述をコピペしてもらえますか。
退会済みユーザー

退会済みユーザー

2015/10/11 19:35 編集

エラーの内容まで詳しく回答ありがとうございます。 ご指摘の通りcount =2にしましたらindexを表示することが出来ました。 ですが、どの画像をクリックしても Missing template photoposts/vote, application/vote with....... が発生する様になってしまいました。 なぜvoteをgetで取得する様に変わってしまったのでしょうか? 追記:試しに全くコードを書いていないvote.html.erbを作り、 正常にクリック→vote.html.erbに遷移出来ましたが、インクリメント、デクリメントが行われませんでした。
退会済みユーザー

退会済みユーザー

2015/10/11 21:07 編集

可能性としてはif文条件合致がなくリダイレクトしてないのでエラーになっているんでしょうね。viewがないとエラーが出るようになったのもそれが原因だと思います。session[:target1]とsession[:target2], params[:id]にちゃんと値が入っていて,session[:target1],session[:target2]と params[:id]のどちらかと等しいことを確認できますか?
退会済みユーザー

退会済みユーザー

2015/10/12 15:52 編集

再度コメントありがとうございます。 貼って頂いた情報を参考にデバッグを行ったのですが、 <% @target1 = Photopost.find(session[:target1]) %> <%= debug (@target1) %> <% @target2 = Photopost.find(session[:target2]) %> <%= debug (@target2) %> 表示されている画像2枚の情報が表示されました。 params[:id]のデバッグ方法が分からなかったので確認出来ていませんが、 つまりこれはparams[:id]を取得出来ていないという解釈でよろしいのでしょうか? 追記:<%= debug (@target1) %>に必ずid:2の情報が表示されてしまいます。。。
退会済みユーザー

退会済みユーザー

2015/10/12 18:48 編集

def vote end のなかで logger.debug(@target1) logger.debug(@target2) さらにparams[:id]から取得したデータを@tempなど適当に変数作って logger.debug(@temp) と書いてください。 コントローラーのファイルがあるフォルダもしくはプロジェクト内のlogフォルダに何らかのファイル名のログが書き出されるはずです。 これで中身が一緒のものがあれば上手くいきます。 idが2になってしまうというのは写真のidは2ではないのにidが2になってしまうということでしょうか?もしくはidが2の写真しか表示されないということでしょうか? indexの書き方を根本的に間違えてる可能性があるので可能であれば写真選出からループで画像表示している部分のDOMをみせていただきたいです。 個人的には諦めないで頑張っていただきたいとは思うのですがrailsのMVCの構造やデータの渡し方やどう写真を特定するかのイメージが出来ていないようであればいたずらに時間を浪費してしまうのでもう少し基礎を固めてから取り組んだ方がいいかもしれません。 例えば写真の特定などはidが一意に定まっていれば写真が選ばれた時にidの値を二つ保存しておいて,クリックされたidをまた別に保存し,クリックされたidと選出された写真のidの値を比較すればいいので,普通はデータを全て持って来て比較ということはメモリを無駄遣いするのでしない方が良かったりします。特にクラスの中には比較演算子がいつでも数式と同じように使えるように定義されてる保証がないのでクラスのインスタンス同士の比較はドキュメントで保証されていないかぎりやらないほうがベターです。(findしたインスタンスで比較していたあたりなど) またparamsはvoteコントローラーURIでアクセスした時にそのURLにパラメータを渡すための連想配列です。あなたが書いているコードでは:id=>photo〜.idによってvoteコントローラーのparamsに写真のidを渡していてクリックした後でvoteコントローラーでparamsを通して写真のidを受け取ることが出来ているのです。なので,クリックするまではparamsは他のページから受け取っていなければ空のままでvoteコントローラーにアクセスしてvoteコントローラー内あるいはvoteのビュープログラム内で値が受け取れるのです。 なので,paramsにもう一枚の写真のidを:idではなく別のキー(:anotherなど任意の名前)で送ることであなたが望んでいる処理を実現することもできます。(この方法はどうやって二枚の写真をランダムで選んだのか分からないのとループが増えるのでセッションを使う方法をおすすめしました。) 覚えることは多いですが,覚えたあとは自由自在に書けるようになるはずなので頑張ってください。
退会済みユーザー

退会済みユーザー

2015/10/13 13:13 編集

詳しく長文回答ありがとうございます。 一度整理したいのですが、イメージとしてはx枚から2枚をランダムに取り出した時点で、sessionを利用しidを保存→クリックされた画像のidと2枚の画像のidをif文で比較、といった感じで合っていますか? 自分の中ではここまでやってきたので、何とか実装まで持って行きたい一心です。。。 写真のidが2ではないのに、idが2と表示されてしまいました。 paramsについての解説を詳しくありがとうございます。 indexにて:id=>photo〜.idを書いていて、urlにパラメータを渡せているので、 params[:id]には問題無いことがよくわかりました。 確かに覚えることが多くて大変です。。。 よく言われるrubyは問題無いがRailsが鬼門の意味がよく理解できました。。 生phpの経験は多少あるのですが、どうせフレームワークを覚えるならRails...は安易な考えだったのかも知れません。。。 debugの件なのですが、@target1が見つからないエラーが発生してしまっている状況で、値が表示されません。 一度コードを追記の部分に更新するので、indexの書き方含め見て頂くことは可能でしょうか?
guest

0

様々なやり方がありますが,見た所voteビューに遷移することがイベントハンドラのトリガーになっているのでsessionを使うのが良いと思います。
index.html.erbのforループ中にランダムで選ばれた2枚の:idを適当なkey(例としてtarget1,target2とします)でsessionに保存する処理(session[:key]=id)を書き足し,コントローラーの voteの定義内にPhotoposts.find(session[:target1])
Photoposts.find(session[:target2])
で別々のインスタンスで取得しif文でparams[:id]とsession[:target]の値の比較等で条件分岐などしてインクリメントとデクリメントを振り分ければいいと思います。詳しくはsession railsなどで資料を探してみてください。

他には画面遷移などがなければ画像にonclick属性を付加して動的にrubyコードを精製して実行させたり,voteコントローラーで実行せずにページにコールバックを設定して画面遷移前に実行したりする方法も考えられます。

投稿2015/10/08 19:12

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2015/10/09 03:24 編集

回答ありがとうございます。 本来実装したかったのがsessionを使う形 なので早速取り入れてみようと思います! ちなみにvote_controllerのみを改良するだけで実装出来ますか?
退会済みユーザー

退会済みユーザー

2015/10/09 06:26

全体の構成が解っていませんが今提示してもらっている構成だけで見ると,画面遷移を行うように組んでいればvote_controllerのみではなくindex.html.erbを書き変える必要があると思います。画面遷移を行なわないのであれば,viewコントローラー内で写真を選ぶロジックを組みそのidを変数に保持し,index.html.erbのブラウンジング時に動的ページとして埋め込むなどの方法も考えられます。
退会済みユーザー

退会済みユーザー

2015/10/09 15:51 編集

画面遷移を行うのでindexも書き換えることにします! と思ったのですが、indexのどこを書き直せば良いのかが分かりません。。
退会済みユーザー

退会済みユーザー

2015/10/11 10:17 編集

indexの方は <%@post〜do〜%>を <% count=1 @post〜do〜%>に <%end%>を <%session[":target"+count++] =photopost.id end%> と書けばいいと思います。これで通らなかったら工夫してみてください。
退会済みユーザー

退会済みユーザー

2015/10/11 12:15

コメントありがとうございます。 頂いた情報を参考にindexを変えたのですが、id = 2以外をクリックするとエラーになってしまう様になってしまったので、クリックした方のみ増やす形で妥協しようと思います。
退会済みユーザー

退会済みユーザー

2015/10/11 15:18 編集

そうですか。お役に立てず申し訳なかったです。 sessionの使い方に誤解があるみたいなのでコントローラーのほうのコードもうまくいかないように書かれています。 ソースを少し直しました。 ``` photoposts_controller.rb def vote @target1 = Photopost.find(session[:target1]) @target2 = Photopost.find(session[:target2]) if session[:target1] == params[:id] @target1.score += 1 @target1.save @target2.score -= 1 @target2.save redirect_to root_url elsif session[:target2] == params[:id] @target1.score -= 1 @target1.save @target2.score += 1 @target2.save redirect_to root_url end end ``` あとごめんなさい。Rubyだと数値型と文字列の暗黙変換とインクリメントがないんですね。以下のように書き直してください。 <%session ~ end%> の部分を <% session[('target'+count.to_s).to_sym]=photopost.id count+=1 end%> 環境を見ながらできればすぐ直せるんですが…。頑張ってください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問