Topic: DRYing up a Private Messaging Controller

The app I'm building utilizes private messaging between the users. The user is allowed to type in one or more usernames to send a message to. Since the users must be looked up separately to see if they are valid usernames, I can't really validate them within the user model. I came up with this.

  def create
    @user      = current_user
    if request.post?
      #sort_recipients returns a hash of valid and invalid usernames
      recipients = sort_recipients(params[:message][:recipient])
      if recipients[:invalid].empty?
        messages = recipients[:valid].collect do |recipient_id|
          @message = Message.new( :sender_id    => current_user.id,
                                  :recipient_id => recipient_id,
                                  :subject      => params[:message][:subject],
                                  :body         => params[:message][:body]) 
        end

        if messages.all?(&:valid?)
          messages.each(&:save!)
          flash[:success]          =  "Message Sent"     
          redirect_to :controller  => "message", :action => "inbox"
        else
          render :action => :create   
        end
       
      else 
        @message = Message.new( :sender_id    => current_user.id,
                                :recipient_id => params[:message][:recipient], 
                                :subject      => params[:message][:subject],
                                :body         => params[:message][:body]) 
        @message.errors.add_to_base("Sorry, the following usernames were invalid:
                                    #{recipients[:invalid].join(', ')}") 
        render :action => :create                                     
      end
    end
  end


As you can see,it is very ugly, and is not very DRY either.
I was thinking I could store the recipient_name instead of the recipient_id in the model...but I wasn't sure if that would end up being much better.

Any help would be appreciated.

Re: DRYing up a Private Messaging Controller

I suppose you've set up associations.. Maybe you can use some of the following. It's four in the morning, so I've possibly missed something. Also I can properly be done in a fancier way..

def create
  if request.post?
    recipients = Recipient.find(:all, :conditions => "username IN (#{params[:message][:recipient].join(',')})")
    unknown_recipients = params[:message][:recipient] - recipients.collect {|r| r.username}
   
    @msg = recipients.inject([]) do |msg,r|
      msg << current_user.messages.new :recipient_id => r.id, :subject => params[:message][:subject], :body => params[:message][:body]
      render :action => :create unless msg.valid?
    end
   
    @msg.each(&:save!)
       
    @message.errors.add_to_base("Sorry, the following usernames were invalid: #{unknown_recipients.join(', ')}") if unknown_recipients
   
    flash[:success] = "Message Sent"
    redirect_to :controller => "message", :action => "inbox"
  end
end

Last edited by mrt (2007-07-23 21:40:08)

Re: DRYing up a Private Messaging Controller

mrt,

Thank you for posting that - I haven't had a chance to go through and work it into my function and/or revise it yet, but it looks pretty much like what I was looking for. Thanks again.

Re: DRYing up a Private Messaging Controller

Does anyone have basic framework for a message system.  I had a look at the easy messages plugin, but im not using act as authenticated.