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

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

ただいまの
回答率

90.83%

  • Ruby

    6574questions

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

  • Ruby on Rails

    6407questions

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

  • Ruby on Rails 4

    2352questions

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

rails4 再読み込み(リロード)するとうまくいくのですが...

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,331

takyas

score 42

Rails4のeach、form_for関連でハマっております。

開発環境
Ruby 2.3
Rails 4.2.5

教えていただきたい箇所は以下です。
Userモデル、Skillモデル、UserSkillモデルがあり、UserのMyPage内でAjaxを使ったSkillの新規登録・編集・削除がしたいです。
今現時点では、新規登録・削除は実装できているのですが、編集の「更新」の部分でハマっております。
1回、「更新」ボタンをクリックしても何も反応しないのですが、リロードして「更新」クリックを押すときちんと更新がされます。
素人が故にどのような情報をこちらに記載すれば、閲覧者様の解決のお力になるのか理解していないので、追加で必要な情報がございましたら、ご教示いただけますと幸いです。 

(Ajaxの部分の追加)
Ajaxの部分は、eachで回したskillのリストの中で、「編集」ボタンが押されたリストの行のみを「編集可能」にするというものです。
「submit」はAjax化しておりません。
説明不足で申し訳ございません。

skillリスト
編集ボタンクリック後
devtool
ルーティング

Userskillカラム
id,user_id,skill_id,level,detail

User has_many :skills
User has_many :user_skills
Skill has_many :users
Skill has_many :user_skills
Userskill belongs_to :user
Userskill belongs_to :skill

users/show.html(Mypage内)

<div id="user_skill">
  <%= render partial: "skill", locals: {user: @user} %>
</div>


users/_skill.html.erb

<table class="table table-striped">
    <thead>
        <tr>
            <th>No.</th>
            <th>スキル</th>
            <th>レベル</th>
            <th>詳細</th>
            <th>編集</th>
            <th>削除</th>
        </tr>
    </thead>
    <tbody>
      <% @user.user_skills.each_with_index do |userskill, i| %>
        <tr class="skill_list_<%= i+1 %>">
            <%= render partial: "skill_list", locals: {i: i, userskill: userskill} %>
        </tr>
      <% end %>
    </tbody>
</table>


users/_skill_list.html.erb

<td><%= i+1 %></td>
<td><%= userskill.skill_id %></td>
<td><%= userskill.level %></td>
<td><%= userskill.detail %></td>
<td><%= link_to '編集', edit_skill_path(userskill, list_num: i+1, uid: current_user.id), remote: true %></td>
<td><%= link_to '削除', edit_destroy_skill_path(userskill), method: :delete %></td>


users/edit_skill.js.erb

$('.skill_list_<%= @list_num %>').html('<%=j render partial: "edit_skill_form", locals: {userskill: @userskill, list_num: @list_num} %>');

users/_edit_skill_form.html.erb

<%= form_for(userskill, url: userskill_path(userskill)) do |f| %>
  <td><%= list_num %></td>
  <td><%= f.select :skill_id, { :html5 => "1", :css3 => "2"} %></td>
  <td><%= f.select :level, { :初心者 => "1", :経験者 => "2", :プロ => "3"} %></td>
  <td><%= f.text_area :detail %></td>
  <td>
    <%= f.submit "更新" %>
  </td>
  <td>
    <%= link_to '戻る', user_path(current_user.id) %>
  </td>
<% end %>


UserskillsController

class UserskillsController < ApplicationController
  before_action :set_skill, only: [:update]

  def update
    respond_to do |format|
      if @userskill.update(userskill_params)
        format.html { redirect_to root_path, notice: 'UserSkill was successfully updated.' }
      end
    end
  end

  private

  def set_skill
    @userskill = UserSkill.find(params[:id])
  end

  def userskill_params
    params.require(:user_skill).permit(:id, :skill_id, :level, :detail)
  end
end


routes.rb

resources :userskills


質問の方法等で不足があればご教示下さい。
「このへんどうなってんの?」等もどんどんご連絡下さい。
宜しくお願い致しますm(_ _)m

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • 退会済みユーザー

    退会済みユーザー

    2016/03/08 00:42

    おそらくバグの原因は JavaScript なので、JavaScript のコードがないとなんとも言えないですね

    キャンセル

  • takyas

    2016/03/08 01:07

    yamagen様 コメントありがとうございます。 javascript部分のコードとご説明、図を追加致しました。 お時間のある時で結構ですので、お知恵をお貸しいただけますと幸いです。

    キャンセル

回答 1

checkベストアンサー

0

サブミット部分をjsのリクエストに変えているという理解でよろしいでしょうか?

ajaxの実装部分が解っていないので推測で書きますが、updateアクションのルーティングされたURLにPUTメソッドでリクエストを行った時にレスポンスが返って来るようにコントローラー側(もしくはルーティング側のフォーマット指定)で設定が必要です。このときformatがhtmlに引っかからず,リダイレクトがかかっていないためサーバ上では更新されているが,リダイレクトがかかっていないため,クライアント側で更新されないという現象が起こっているように思います。

完璧なajaxで実装する場合はフォームに反映させたいレスポンスをコントローラー側で記述し,js側で受け取り,レスポンスをフォームに反映させる処理を書かなければいけません。

追記

追記ありがとうございます。だいぶ見通しが良くなりました。railsの機能でajaxを行いたいなら以下のような例を挙げます。ただ直す方法は沢山あり,これは一例にすぎないこと,エラーチェックをこちらからはできないのでこのコードでも動作が上手くいかない可能性もあるので,どういう方針で直すのか参考程度のものと思っていただければと思います。パラメータの意味などは適宣調べてもらえると助かります。変更を加えた行にはコメントをつけました。

#_edit_skill_form.html.erb
<%= form_for(userskill, url: userskill_path(userskill),{remote:true,method:PUT}) do |f| %> #処理をAjaxにPUTメソッドを明示的に
  <%=  f.hidden_field :list_num, :value => list_num % > #list_numでどの行のUserSkillを変えたか識別する
  <td><%= list_num %></td>
  <td><%= f.select :skill_id, { :html5 => "1", :css3 => "2"} %></td>
  <td><%= f.select :level, { :初心者 => "1", :経験者 => "2", :プロ => "3"} %></td>
  <td><%= f.text_area :detail %></td>
  <td>
    <%= f.submit "更新" %>
  </td>
  <td>
    <%= link_to '戻る', user_path(current_user.id) %>
  </td>
<% end %>

#file追加
Userskill/update.js.erb

$('.skill_list_<%= @list_num %>').html('<%=j render partial: "skill_list", locals: {userskill: @userskill, list_num: @list_num} %>'); #Ajaxコード
#UserskillsController.rb

def update
    respond_to do |format|
      if @userskill.update(userskill_params)
        format.html { redirect_to root_path, notice: 'UserSkill was successfully updated.' }
        format.js #アクションと同名の.js.erbコードのレンダリング
      end
    end
  end

def set_skill
  @userskill = UserSkill.find(params[:id])
  @list_num = params[:list_num] if params.key?(:list_num) #リストの何番目からのリクエストか記憶
end


エラーなどが出てしまった場合は引数などが変わっているところを参考に,適宣修正してください。方針としてはajaxで書き換えたDOMをupdateメソッドの実行後に違うajaxコードを読み込んで元に戻すという方法です。
Userskill/update.js.erbのフォルダ位置が気持ち悪い場合は(hogeは任意の名前),Users/hoge.js.erbを作成し,UserskillsController.rbでのrender: {template: users/hoge.js.erb}を使って参照先を変更して@list_numの受入先を修正してください。

画面遷移を許すのであれば,

#_edit_skill_form.html.erb
<%= form_for(userskill, url: userskill_path(userskill),{method:PUT}) do |f| %>#ajaxではなくredirectで更新する。PUTメソッドを明示的に
  <%=  f.hidden_field :list_num, :value => list_num % > #list_numでどの行のUserSkillを変えたか識別する
  <td><%= list_num %></td>
  <td><%= f.select :skill_id, { :html5 => "1", :css3 => "2"} %></td>
  <td><%= f.select :level, { :初心者 => "1", :経験者 => "2", :プロ => "3"} %></td>
  <td><%= f.text_area :detail %></td>
  <td>
    <%= f.submit "更新" %>
  </td>
  <td>
    <%= link_to '戻る', user_path(current_user.id) %>
  </td>
<% end %>
#UserskillsController.rb

def update
    respond_to do |format|
      if @userskill.update(userskill_params)
        format.html { redirect_to root_path, notice: 'UserSkill was successfully updated.' }
        format.js { redirect_to root_path, notice: 'UserSkill was successfully updated.' } #js formatの時に処理が定義されていないのが原因であればリダイレクトする事で直るかも
      end
    end
  end

def set_skill
  @userskill = UserSkill.find(params[:id])
  @list_num = params[:list_num] if params.key?(:list_num) #render用にlist_numを記憶
end

とやればリダイレクトで更新かけれると思います。

ただ現在のコードを見ると,フォームのメソッドがデフォルトのPOSTになっている気がしていて,updateアクションが呼ばれず,正常に更新できないように思えるので,更新されるという事に違和感があって,直接的なバグの原因がちょっと直感的に分かり兼ねています。PUTでリクエストすべきアクションがPOSTになっていた(これだとupdateメソッド自体呼ばれないはず),formatがjsでリクエストされた時の動作を返していない(format.htmlは記憶違いでなければ該当フォーマットがない時にもhtml返すんじゃなかったっけ?)事くらいかなと予測しています。(が,あまり釈然としていません)。
もしかすると他の要因も絡んでいるかもしれないので,binding.pryなどを使ってupdateにリクエストが飛んでいるか。formatが正しいかsaveメソッドは成功しているか,指定されたHTTPメソッドは正しいかなど調べてみてください。

#UserskillsController.rb

def update
    respond_to do |format|
     binding.pry #break point
      if @userskill.update(userskill_params)
     binding.pry #break point
        format.html { redirect_to root_path, notice: 'UserSkill was successfully updated.' }
      end
    end
  end

def set_skill
  @userskill = UserSkill.find(params[:id])
  @list_num = params[:list_num] if params.key?(:list_num)
end


など上記のようにブレイクポイントを貼って変数の中身やちゃんとupdateが呼ばれているかなどを調べてみてください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/03/08 01:13

    tkow様
    コメントありがとうございます。
    また、説明不足で申し訳御座いません。
    今回Ajaxの部分は、submitではなく「編集」ボタンのlink_toの部分でございます。
    ```
    updateアクションのルーティングされたURLにPUTメソッドでリクエストを行った時にレスポンスが返って来るようにコントローラー側(もしくはルーティング側のフォーマット指定)で設定が必要です。このときformatがhtmlに引っかからず,リダイレクトがかかっていないためサーバ上では更新されているが,リダイレクトがかかっていないため,クライアント側で更新されないという現象が起こっているように思います。
    ```
    正直申し上げてこのご助言いただきました箇所の理解が浅いので、キーワードを拾ってググってみます。
    また、javascriptのコード・ご説明、図を追加致しましたので、ご確認いただき、新たにお気付きの点がございましたら、ご助言いただけますと幸いです。

    キャンセル

  • 2016/03/08 23:36 編集

    tkow様
    再コメント(コメントのレベルではなく、解説・リファクタリングのレベルですが)本当にありがとうございます!
    まだ、ご教示いただきましたアドバイスを参考にしての実装には取り掛かれてはいないのですが、このコメントを投稿後取り掛かります!!
    また開発中でハマった時に、ここ(teratail)に投稿することもあるかと思いますが、その際は是非宜しくお願い致しますm(_ _)m
    本当にありがとうございます!

    (追記)
    tkow様がおっしゃられています。
    「ただ現在のコードを見ると〜」のPUTの部分に関しては、PUTではなくPATCHがhiddenで渡されており、そのルーティングでuserskills#updateが呼ばれているようです。
    画像をUP致します。

    キャンセル

  • 2016/03/09 00:08

    そう言えばrailsはedit
    _formだとデフォルトPATCHで実行してくれるとかあるんでしたっけ。
    であればupdateメソッドがtrueになってるか。なっていれば正しくレスポンスが返せてるか、リダイレクト出来てるかあたりを調べれば原因が特定出来ると思います。webrickの出力ログなんかも参考になると思います。頑張って下さい。

    キャンセル

  • 2016/03/09 20:08

    tkow様
    コメントありがとうございます。
    アドバイス頂きました内容を参考にさせていただき、原因を追求したところ、解決まではいっていないのですが、解決の糸口の部分までは見えてきました。
    このエントリの内容とは違った部分に原因がありそうです。
    今一度エントリする予定ですので、お時間に余裕がございましたら、チラ見していただけますと幸いです。

    キャンセル

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

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

関連した質問

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

  • Ruby

    6574questions

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

  • Ruby on Rails

    6407questions

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

  • Ruby on Rails 4

    2352questions

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