Rails - how do I validate existence of a row refer

2019-03-24 16:07发布

问题:

Given that the "Rails Way" seems to be not to use foreign key constraints, I'm looking for an alternative that will allow me to validate that the row a foreign key references does in fact exist in TableA before I save an object in TableB with table_a_id.

The only resource I've found to do this so far (can't find a link to the blog post it was mentioned in, was dated 2007) doesn't appear to be compatible with Rails 3.2, so can anyone suggest a way of doing this?

I'm currently looking at creating a validator to manually assign to the relevant attributes in my models, but I can't work out how to do it with validate_each(object, attribute, value).

回答1:

There is a plugin that helps you with this for belongs_to associations: Validates existence of. But, maybe you can add your own validation? What about something like this:

# Assuming your foreign key is user_id (which references the table User)
validate :user_id_exists

def user_id_exists
  return false if User.find_by_id(self.user_id).nil?
end


回答2:

simply use like below,

validates :user, presence: true

It will automatically check the existence of user record in db.



回答3:

I had problems with this piece of code:

return false if User.find(self.user_id).nil?

I had to catch the ActiveRecord exception when no matching record was found. nil? does not work when no record is found; the exception is thrown before nil? is executed.

# Assuming your foreign key is user_id (which references the table User)
validate :user_id_exists

def user_id_exists
  begin
    User.find(self.user_id)
  rescue ActiveRecord::RecordNotFound
    errors.add(:user_id, "user_id foreign key must exist")
    false
  end
end

This is useful when you use invalid? assertions in unit tests.

request.user_id = unknown
assert request.invalid?

request.user_id = 1
assert request.valid?


回答4:

Note that as of Rails 3.2, the validates_presence_of works exactly the way you want it to in this case and you don't have to build a complicated structure like the above answers or even use the nice validates_existence_of gem.



回答5:

I dislike exceptions. I solved this problem by doing this:

class Foo < ActiveRecord::Base

    validate :bar_exists

    protected

    def bar_exists
        if !User.where(bar_id: self.bar_id).exists? then
            errors.add(:bar_id, 'A valid bar_id is valid.')
        end
    end

end


回答6:

You need to specify the inverse_of option and validate that it's presence is true.

From the Active Record Validations Guide:

In order to validate associated records whose presence is required, you must specify the :inverse_of option for the association