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

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

ただいまの
回答率

90.50%

  • Ruby

    7680questions

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

  • Ruby on Rails 4

    2438questions

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

Ruby on Rails メッセージ機能でのメッセージの取得について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 610

riamk

score 32

前提・実現したいこと

rails4 ローカル環境

現在メッセージ機能を実装してラインのようなメッセージのやりとりができるようにしたいと思っています。 

発生している問題・エラーメッセージ

メッセージ機能は無事に実装できて、メッセージのやり取りをしているページで『相手のメッセージは左側』『自分のメッセージは右側』という表示の仕方にしようと思ったのですが、相手のメッセージがCouldn't find User with 'id'=とエラーになり表示できません。

最初に試してみたときは正常に表示できたのですが、機能テストのためユーザーを増やして試してみたところ、先ほどのCouldn't find User with 'id'=というエラーになってしまいました。

あと、

<% if @over_ten %>
   <%= link_to '以前のメッセージをすべて表示', '?m=all' %>
<% end %>


とこのように10件以上の表示はリンクをクリックして表示させているのですが、正常に表示さえているユーザーとのメッセージもこのリンクをクリックするとCouldn't find User with 'id'=と同じようにエラーになってしまいます。

該当のソースコード

問題があると思われるviewのコード。
また、今回メッセージ機能は会話「conversations」、メッセージ「messages」として関連づけて作成したので、そちらのコントローラーとモデルなども記載します。

views/messages/index.html.erb

    <% if @over_ten %>
      <%= link_to '以前のメッセージをすべて表示', '?m=all' %>
    <% end %>

    <div class="ui segment">
      <% @messages.each do |message| %>
        <% if message.user_id == current_user.id %>
          <!-- 自分のメッセージ -->
          <div class="item-right">
            <% user = User.find(message.user_id) %>
            <strong><%= user.name %></strong>
            <%= message.message_time %>
            <%= message.body %>
          </div>
        <% else %>
          <!-- 相手のメッセージ -->
          <div class="item-left">
            <% user = User.find(message.user_id) %>
            <strong><%= user.name %></strong>
            <%= message.message_time %>
            <i class="right triangle icon"></i>
            <%= message.body %>
          </div>
        <% end %>
      <% end %>
    </div>

    <!-- メッセージの送信 -->
    <%= form_for [@conversation, @message], html: {class: "ui reply form"} do |f| %>
      <div class="field">
        <%= f.text_area :body, class: "form-control" %>
      </div>
      <%= f.text_field :user_id, value: current_user.id, type: "hidden"  %>
      <div>
        <%= f.submit "メッセージを送る" %>
      </div>
    <% end %>

messages_controller.rb

class MessagesController < ApplicationController
  before_action :authenticate_user!

  before_action do
    @conversation = Conversation.find(params[:conversation_id])
  end

  def index
    @messages = @conversation.messages
    if @messages.length > 10
      @over_ten = true
      @messages = @messages[-10..-1]
    end

    if params[:m]
      @over_ten = false
      @messages = @conversation.messages
    end

    if @messages.last
      if @messages.last.user_id != current_user.id
       @messages.last.read = true
      end
    end

    @message = @conversation.messages.build
  end

  def create
    @message = @conversation.messages.build(message_params)
    if @message.save
      redirect_to conversation_messages_path(@conversation)
    end
  end

  private
    def message_params
      params.require(:message).permit(:body, :user_id)
    end

messageモデル

class Message < ActiveRecord::Base
  belongs_to :conversation
  belongs_to :user

  validates_presence_of :body, :conversation_id, :user_id
  def message_time
    created_at.strftime("%m/%d/%y at %l:%M %p")
  end
end

conversations_controller.rb

class ConversationsController < ApplicationController

  before_action :authenticate_user!

  def index
    @users = User.all
    @conversations = Conversation.all
  end

  def create
    if Conversation.between(params[:sender_id], params[:recipient_id]).present?
      @conversation = Conversation.between(params[:sender_id], params[:recipient_id]).first
    else
      @conversation = Conversation.create!(conversation_params)
    end

    redirect_to conversation_messages_path(@conversation)
  end

  private
    def conversation_params
      params.permit(:sender_id, :recipient_id)
    end
end

Conversationモデル

class Conversation < ActiveRecord::Base
  belongs_to :sender, foreign_key: :sender_id, class_name: 'User'
  belongs_to :recipient, foreign_key: :recipient_id, class_name: 'User'
  has_many :messages, dependent: :destroy
  validates_uniqueness_of :sender_id, scope: :recipient_id
  scope :between, -> (sender_id,recipient_id) do
    where("(conversations.sender_id = ? AND conversations.recipient_id =?) OR (conversations.sender_id = ? AND  conversations.recipient_id =?)", sender_id,recipient_id, recipient_id, sender_id)
  end

  def target_user(current_user)
    if sender_id == current_user.id
      User.find(recipient_id)
    elsif recipient_id == current_user.id
      User.find(sender_id)
    end
  end
end

データベーステーブル

  create_table "messages", force: :cascade do |t|
    t.text     "body"
    t.integer  "conversation_id"
    t.integer  "user_id"
    t.boolean  "read",            default: false
    t.datetime "created_at",                      null: false
    t.datetime "updated_at",                      null: false
  end
  add_index "messages", ["conversation_id"], name: "index_messages_on_conversation_id", using: :btree
  add_index "messages", ["user_id"], name: "index_messages_on_user_id", using: :btree

  create_table "conversations", force: :cascade do |t|
    t.integer  "sender_id"
    t.integer  "recipient_id"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
  end

どのように相手のメッセージを取得したらいいのか教えて頂けると嬉しいです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

errorは

<% else %>
          <!-- 相手のメッセージ -->
          <div class="item-left">
            <% user = User.find(message.user_id) %> 
            <strong><%= user.name %></strong>


<% user = User.find(message.user_id) %> 
ここで発生しているようです。
おそらくmessage.user_idが正しく入っていないmassageがあるということでしょう。
つまり名無しによって投稿されたメッセージがあるということです。

<% else %>
          <!-- 相手のメッセージ -->
          <div class="item-left">
            <% user = User.find_by(id: message.user_id) %> 
            <strong><%= user.try(:name) %></strong>


とすれば、とりあえず、エラーメッセージは出なくなると思いますが。
誰の発言かわからないメッセージを許容するということで
ソフトウェア的にはバグだということに注意してください

もし、名無しメッセージが増えるようでしたら、messages_controller.rbとviews/_form.html.erb views/new.html.erbも晒してください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/28 15:28

    ご回答ありがとうございます。
    さっそく教えて頂いたコードのように試してみましたが、
    undefined method `strftime' for nil:NilClass
    とエラーが出てしまいました。
    なぜ、strftimeがエラーになってしまうのか分からず苦戦しております。

    コントローラーやモデル、テーブルなど、現在のコードを追記しましたので、再度アドバイス頂けると嬉しいです。

    キャンセル

  • 2017/03/28 16:14

    massage.created_at
    も登録されていないようですね
    これも
    def message_time
    created_at.try(:strftime,"%m/%d/%y at %l:%M %p")
    end
    とすればとりあえずエラー回避は可能です。
    これ以上解説が必要でしたら
    さらに
    massages_controllers.rbの
    def message_params

    app/views/massages/_form.html.erb app/views/massages/new.html.erb
    も見せてください

    キャンセル

  • 2017/03/28 20:37

    ありがとうございます!
    とりあえずは無事に表示できました。

    massages_controllers.rbのdef message_paramsは追記しました。

    app/views/massages/_form.html.erb
    app/views/massages/new.html.erb
    この2点に関しては現時点では作成していません。

    現状は正常に表示できていますが、何か修正した方がいいポイントなどご指摘があれば教えて頂けると嬉しいです。

    キャンセル

  • 2017/03/28 20:56

    Massage controller のindex内の
    @message = @conversation.messages.build

    message = @conversation.messages.build(user: current_user)にしてみてはいかがでしょう?

    キャンセル

  • 2017/03/28 21:33

    ご指摘ありがとうございます。
    message = @conversation.messages.build(user: current_user)
    にしてみたところ、
    First argument in form cannot contain nil or be empty
    とエラーになったので
    @message = @conversation.messages.build(user: current_user)
    としました。

    表示は正常にできていますが問題はありますでしょうか?

    キャンセル

  • 2017/03/28 22:16 編集

    @が抜けてましたねそれで大丈夫です。それでうまくいくと思います。

    キャンセル

  • 2017/03/28 22:27

    はい、現状はこれでうまくいっています。
    ありがとうございました。

    私はまだ初心者で全然分からないことばかりですが、機会があればまたよろしくお願いします。

    キャンセル

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

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

関連した質問

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

  • Ruby

    7680questions

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

  • Ruby on Rails 4

    2438questions

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