I have a user-to-user messaging system. I'm trying to pass an array of user ids to a ConversationUser
(join table) model which would then create multiple conversation_users
from each individual user.id
. The two fields in ConversationUser
are conversation_id
and user_id
. I'm able to initialize a single conversation user because the new conversation_id
is being passed along to the model, but for some reason, the hash of user ids is not getting to my model. I'm getting a Validation failed: User can't be blank
My conversation/new view for capturing the user_ids:
<%= check_box_tag "conversation_user[recipient][]", user.id %> <%= user.name %><br />
I know this is working because part of my params that I'm receiving back are:
"conversation_user"=>{"recipient"=>["9", "10"]}
The essentials of my Rails 4 controller & strong params:
class ConversationsController < ApplicationController
def new
@user = User.find(params[:user_id])
@conversation = @user.conversation_users.build
@conversation.build_conversation.messages.build
end
def create
@conv = Conversation.create!
@conversation = @conv.conversation_users.create!(conversation_user_params)
end
def conversation_user_params
params.require(:conversation_user).permit(recipient: [])
end
The essentials of my ConversationUser model:
class ConversationUser < ActiveRecord::Base
attr_accessor :recipient
before_create :acquire_conversation
validates :user_id, :conversation_id, presence: true
def acquire_conversation
unless recipient.blank?
recipient.each do |u|
ConversationUser.create(user_id: u, conversation: conversation)
end
end
end
end
I think the problem is somewhere in my controller's conversation_user_params
. But it also might be in the model's before_create
method. I've been trying to fix this problem for a day now, with lots of debugging with no success. If anyone can be of assistance, I thank you in advance.
The problem is in the model. before_create
callback is called before creating a ConversationUser
. Let's name this created ConversationUser
as CURRENT
. So, before creating the CURRENT
ConversationUser
you loop through recipient ids and create a ConversationUser
for each of them. The ConversationUser
s that you are creating here are not CURRENT
ConversationUser
. CURRENT
ConversationUser
is saved after the callback is executed (after you create other ConversationUser
s). But in this case CURRENT
ConversationUser
doesn't know wich User
it belongs to, because you pass user_id
parameter to ConversationUser
s that you create in before_create
callback, but you do not pass it to CURRENT
ConversationUser
when it is created (when original create!
method is executed).
To solve this problem you can override original create!
method or not use it at all for creating ConversationUser
s by recipient ids. Add a new method to your Conversation
model (for example create_conversation_users
):
Solution
In the controller:
def create
@conv = Conversation.create!
@conversation = @conv.create_conversation_users!(conversation_user_params[:recipient])
end
In the model:
class Conversation
def create_conversation_users!(recipient_ids)
return if recipient_ids.blank?
recipient_ids.each do |recipient_id|
conversation_users.create!(user_id: recipient_id, conversation: self)
end
end
end
You should also update ConversationUser
model:
class ConversationUser < ActiveRecord::Base
validates :user_id, :conversation_id, presence: true
end