Bitwise
Bitwise

Reputation: 8461

Setting Rails Validations. Using two models in one form

I have a Group model and a Message model, each are HABTM. I'm trying to set a validation for my main form which is to send out a SMS to certain groups. Right now I have the body of message validated with presence: true, that is working fine but in my Group model I want to validate name to be present but how to I have them both validate when I'm calling a create method in the messages controller? I'll show my code for more clarification.

Here is group.rb

  class Group < ActiveRecord::Base
   has_and_belongs_to_many :people
   has_and_belongs_to_many :messages
   validates :name, presence: true 
  end

Now message.rb

class Message < ActiveRecord::Base
  has_and_belongs_to_many :groups

  validates :body, presence: true
end

Here is my message_controller.rb

def create
@message = Message.create(message_params)
if @message.save
  run_at_time = @message.send_at.present? ? @message.send_at : Time.zone.now
  people = Person.in_groups(message_params[:group_ids])
  if people.any?
    people.each do |person|
      person.delay(run_at: run_at_time).send_message(@message.body)
    end
    flash[:success] = "Messages on their way!"
  end
  redirect_to root_path
else
  render "new"
end
end

enter image description here

For more understanding I want my form to display "Groups can't be blank" as well as "body can't be blank". If nothing is selected.

Upvotes: 1

Views: 704

Answers (2)

max pleaner
max pleaner

Reputation: 26758

Using valid? was the first thing that came to mind, but there is another way as well.

Model validations actually have built-in support for assoiations.

For example,

class Message
  has_and_belongs_to_many :groups
  validates :groups, presence: true
end

See this StackOverflow answer.

So this would cause save to fail if the message had no groups.

There's always another way - you can override valid?, which is called internally by save. For example:

class Message
  def valid?(*args)
    original_result = super(*args)
    if self.groups.empty?
      self.errors_add(:groups, "cannot be empty")
      return false
    end
    return original_result
  end
end

This is largely the same thing accomplished by validates :groups, presence: true, although I think presence: true will also verify that the foreign keys refer to valid records (rather than just checking that any associated record exist).

Calling valid? has the side effect of loading up the errors object. For example:

  msg = Message.new
  msg.errors.full_messages # => []
  msg.valid? # => false
  msg.errors.full_messages # => ["Name cant be blank", "Groups cant be blank"]
  msg.save # => false

Upvotes: 1

Anatoliy Tszyan
Anatoliy Tszyan

Reputation: 61

If you want to validate multiple models before saving or collect all errors, you could do it by using model.valid? method. It will return true of false, depending on whether there are any errors. And errors will be added to model.errors.

Upvotes: 2

Related Questions