1

I have the following setup that works fine without validation but I wanna write one to make sure there is a user always associated with the product.

So without validation everything is okay. If I fill my product form (for rest of the data) and add this line @product.product_users.build(user_id: current_user.id, role: "owner") in the controller then both the Product with its attrs and the ProductUser with user_id: current_user.id and role: "owner" gets saved. But if I add the following validation then the product doesn't get created and it says the validation doesn't pass. ("There is no user associated")!

def product_users_limit(min: 1)
  if product_users.count < min
    errors.add :base, "There is no user associated!"
  end
end

What's wrong with this validation?

models

User has_many :products, through: :product_users
User has_many :product_users
Product has_many :users, through: :product_users
Product has_many :product_users
ProductUser belongs_to :user
ProductUser belongs_to :product

product_users table

create_table "product_users", force: :cascade do |t|
  t.integer "user_id",    null: false
  t.integer "product_id", null: false
  t.string  "role",       null: false
end

products controller

def create
  @product = Product.new(product_params)
  @product.product_users.build(user_id: current_user.id, role: "owner")
  authorize @product
  if @product.save
    ........

UPDATE

The following validation works with count. The industries must be chosen in the form via select. The product <-> industry setup is the same like product <-> user. The only difference that these are submitted in the form.

def product_industries_limit(max: 5, min: 1)
  if industries.reject(&:marked_for_destruction?).count > max
    errors.add :base, "You can't choose more than #{pluralize(max, 'industry')}."
  elsif industries.reject(&:marked_for_destruction?).count < min
    errors.add :base, "You have to choose at least #{pluralize(min, 'industry')}."
  end
end
Sean Magyar
  • 2,360
  • 1
  • 25
  • 57

1 Answers1

4

Add this stage your product_users.count call trigger a database query and the associated records are not yet created. Use size instead.

Relevant : ActiveRecord: size vs count

Community
  • 1
  • 1
Fred
  • 1,607
  • 20
  • 33
  • Fred, it works, but it's super weird. I use count for the rest of the validations that work (question updated). The only difference that those are submitted via the form. Why is that so? – Sean Magyar May 20 '16 at 15:59
  • Your call to reject will convert the association to an array. And so, the count method is the one from Array. So all happens in memory ;-) – Fred May 20 '16 at 16:00
  • Fred, could you recommend me some extra resources besides the previous one? I mean like not only the difference between count vs size vs length, but when I should use which and why? I've read a bit about it before, but it's always about speed. So for example I had no clue it could be important for validations. – Sean Magyar May 20 '16 at 16:08