mr_muscle
mr_muscle

Reputation: 2900

Rails ActionController::ParameterMissing (param is missing or the value is empty

I used this guide as a starting point for creating a messaging system from scratch. I had to modify these to handle messages between User and AdminUser. For some reason, whenever I now try to create a new conversation by clicking in my view the following link:

<li><%= link_to admin.email, conversations_path(sendable_id: current_user.id, recipientable_id: admin.id), method: :post %></li>

I encounter the error:

ActionController::ParameterMissing (param is missing or the value is empty: conversation Did you mean? controller authenticity_token action recipientable_id):

Params are:

=> #<ActionController::Parameters {"_method"=>"post", "authenticity_token"=>"pHmi9kWBLSc5QSJUPQxfNsqSR1fqWCSCBqEVgRMljhgrxB9g4M0ClsdEi2hBLCTjrLLl774T-mnyK8m40LFhNA", "recipientable_id"=>"1", "sendable_id"=>"2", "controller"=>"conversations", "action"=>"create"} permitted: false>

I am directed to the params.permit line in my controller:

class ConversationsController < BaseController
  def index
    @users = User.all
    @admins = AdminUser.all
    @conversations = Conversation.all
  end

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

    redirect_to conversation_messages_path(@conversation)
  end

  private

  def conversation_params
    params.require(:conversation).permit(:sendable_id, :recipientable_id)
  end
end

If I remove require(:conversation) I'll get an error:

Validation failed: Sendable must exist, Recipientable must exist

Models:

class User < ApplicationRecord
  has_many :conversations, as: :sendable
  has_many :conversations, as: :recipientable
end


class AdminUser < ApplicationRecord
  has_many :conversations, as: :sendable
  has_many :conversations, as: :recipientable
end

class Conversation < ApplicationRecord
  belongs_to :sendable, polymorphic: true
  belongs_to :recipientable, polymorphic: true
  has_many :messages, dependent: :destroy

  validates :sendable_id, uniqueness: { scope: :recipientable_id }
end

class Message < ApplicationRecord
  belongs_to :conversation
  belongs_to :messageable, polymorphic: true

  validates_presence_of :body
end

schema:

create_table "conversations", force: :cascade do |t|
    t.string "sendable_type"
    t.bigint "sendable_id"
    t.string "recipientable_type"
    t.bigint "recipientable_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["recipientable_type", "recipientable_id"], name: "index_conversations_on_recipientable"
    t.index ["sendable_type", "sendable_id"], name: "index_conversations_on_sendable"
  end

Upvotes: 0

Views: 670

Answers (1)

Joel Blum
Joel Blum

Reputation: 7878

You need to help Rails understand which polymorphic models you are referencing; if you only provide ids it fails because Rails also needs the polymorphic type (remember: the type is mandatory so Rails can make the link to the actual table. In your case there are two possible types User and AdminUser)

Simply provide the polymorphic types and also add them to the conversation_params method. From looking at your code I'm guessing this is what you're after:

<li><%= link_to admin.email, conversations_path(sendable_id: current_user.id, sendable_type: 'User', recipientable_id: admin.id, recipientable_type: 'AdminUser'), method: :post %></li>

Upvotes: 1

Related Questions