Rails Nested With_Option :If Used in Validation

Rails nested with_option :if used in validation

You are right that when nesting two :if conditions, the inner one will replace the outer one and always be checked. A workaround to handle two levels of nesting is:

with_options :unless => !(outer condition) do
with_options :if => (inner condition) do

The if and unless conditions do not overwrite each other. I'm not sure I would call this a bug, but it would be nice if you could nest multiple :if conditions.

Send data from radio button to controller for validation of nested attribute value in Rails

  1. In your snippet, 'Check Answer' is merely a link. Since you want to send multiple attributes when clicking on it, you probably want to submit a form instead.
  2. The second parameter of radio_button_tag is the value that your controller will receive in the params. Instead of p.is_answer, you probably want to have p.id.

Documentation for forms

Documentation for radio buttons

P.S. on why you should send the option's id instead: I'm not sure what your business use case is, but if you want to identify which option the user picked, you want to send an option identifier, i.e. the id of the option. Furthermore, a user can send this param without knowing which option is correct. If this is school test, a student could then cheat :)

Error in custom uniqueness validation for rspec

I have a guess at what's happening. I think a fix would be to change your validation with the following line:

product.variants.reload.each do |v|

What I think is happing is that when you call variant1 in your test, it is running the validation for variant1, which calls variants on the product object. This queries the database for related variants, and gets an empty result. However, since variant2 has the same actual product object, that product object will not re-query the database, and remembers (incorrectly) that its variants is an empty result.

Another change which might make your test run is to change your test as follows:

before do
@variant2 = FactoryBot.create(:variant, product_id: product.id, option_values: variant1.option_values)
end

It is subtle and I'd like to know if it works. This sets the product_id field on variant2, but does not set the product object for the association to be the actual same product object that variant1 has. (In practice this is more likely to happen in your actual code, that the product object is not shared between variant objects.)

Another thing for your correct solution (if all this is right) is to do the reload but put all your save code (and your update code) in a transaction. That way there won't be a race condition of two variants which would conflict, because in a transaction the first must complete the validation and save before the second one does its validation, so it will be sure to detect the other one which just saved.

Some suggested debugging techniques:

  • If possible, watch the log to see when queries are made. You might have caught that the second validation did not query for variants.
  • Check the object_id. You might have caught that the product objects were in fact the same object.
  • Also check new_record? to make sure that variant1 saved before you tested variant2. I think it does save, but it would have be nice to know you checked that.

accessing data on a Model's associated Model to perform validations

You're getting that error because you're trying to call the #school method within the context of your class instead of within an instance of your class, and #school is an instance method.

To call instance methods when constructing your validation format Regexp, you can provide a lambda as the :with option, as follows:

validates :email,
:message => "Must be a valid email",
:format => { :with => lambda {|user| /\A[\w+\-.]+@#{Regexp.quote(user.school.email_domain)}\z/i } }

This lambda will be invoked on your model instance, allowing you to call methods on your User instance such as #school. See the documentation for validates_format_of for more details.

Modify error messages for validation with an option

I found these tags in my app. One of those should work for you!

equal_to: must be equal to %{count}
greater_than: must be greater than %{count}
greater_than_or_equal_to: must be greater or equal to %{count}
less_than: must be less than %{count}
less_than_or_equal_to: must be less or equal than %{count}
too_long:
one: 'is to short (max than: 1 character)'
other: 'is to long (max than: %{count} characteres)'
too_short:
one: 'is to short (min: 1 character)'
other: 'is to short (min: %{count} characteres)'
wrong_length:
one: doesn't have the right length (1 character)
other: doesn't have the right length (%{count} characteres)
other_than: must be different than %{count}

How do I refactor this object to lessen dependency on callbacks?

If they checked 'billing address same as shipping address', you shouldn't even try to validate or save a separate billing address, and therefore it shouldn't have any validation errors.

Since the form submit is creating multiple models, I'd suggest a separate OrderBuilder service object (there might be a better name) that you call from the controller. That way your order model doesn't need to be so concerned with clearing address errors. Your order builder can take care of creating the order and any address records, or copying over shipping address to billing address fields.

Also, your 'bill_to_shipping' should definitely be a boolean in the database. If you need to do any converting of the params to boolean, do it at the time you're saving the record, not every time you get it from the database.

Rails - grouped_options_for_select

The grouped_options_for_select method indeed is the correct one.
Since you haven't provided code, this should result in the grouped options you want:

grouped_options_for_select [['Fruits',  @fruits.collect {|v| [ v.name, v.id ] }],
['Veggies', @veggies.collect {|v| [ v.name, v.id ] }],
['Junk', @junk_food.collect {|v| [ v.name, v.id ] }]]

Which can be used to create the dropdown:

select_tag 'Food', grouped_options_for_select(...)

or with form_helper:

f.select :food_attribute, grouped_options_for_select(...)

Is there any way to keep validate field optional in rails?

You could use a conditional validation to achieve what you want:

See here: http://guides.rubyonrails.org/active_record_validations.html#conditional-validation

However, this can quickly get hard to manage. Depending on the condition you're switching on, it'd probably be a cleaner design to use a 'Form Object' which will give you more control and let you do validations without the messy conditional logic.

See section #3 of this blog post for more detail:
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

Using this pattern, you would check for your condition in the controller then determine which form object to send to the view.



Related Topics



Leave a reply



Submit