Rails 3 cannot check for an object if the collection_singular_ids = ids method is used

Is there a way to avoid automatically saving an object when assigning collection attributes (collection_singular_ids = ids method)?

for example, I have the following test and package model, the package has many tests. The user can create a batch package with a number of tests.

# test.rb class Test < ActiveRecord::Base end # package.rb class Package < ActiveRecord::Base has_many :package_tests has_many :tests, :through => :package_tests belongs_to :category validate :at_most_3_tests private # tests count will differ depends on category. def at_most_3_tests errors.add(:base, 'This package should have at most three tests') if test_ids.count > 3 end end # package_test.rb class PackageTest < ActiveRecord::Base belongs_to :package belongs_to :test validates_associated :package end 

There is no validation issue when the package object is new .

 1.9.2 :001> package = Package.new(:name => "sample", :cost => 3.3, :test_ids => [1,2,3,4]) => #<Package id: nil, name: "sample", cost: 3.3> 1.9.2 :002> package.test_ids => [1, 2, 3, 4] 1.9.2 :003> package.save => false 1.9.2 :004> package.save! ActiveRecord::RecordInvalid: Validation failed: This package should have at most three tests 1.9.2: 005> package.test_ids = [1,2] => [1, 2] 1.9.2 :005> package.save! => true 

But I could not use the at_most_3_tests method with the saved package object.

Registration of a record in a table is created immediately when assigning test identifiers

 1.9.2: 006> package => #<Package id: 1, name: "sample", cost: 3.3> 1.9.2: 007> package.test_ids => [1,2] 1.9.2: 007> package.test_ids = [1,2,3,4,5] => [1,2,3,4,5] 1.9.2: 008> package.test_ids => [1,2,3,4,5] 

The client requirement is a drop-down interface for selecting several tests in the form of a package and also use the select2 jquery plugin for the drop-down list. Rhmtl code looks like

 <%= form_for @package do |f| %> <%= f.text_field :name %> <div> <label>Select Tests</label> </div> <div> <%= f.select "test_ids", options_for_select(@tests, f.object.test_ids), {}, { "data-validate" => true, :multiple => true} %> </div> 

Please help me solve this problem.

+5
source share
2 answers

For the limit number of associations

Instead of your method, you can use the following checks as:

 has_many :tests, :length => { :maximum => 3 } 

To use multiple selection

I have this problem before and I decided to use the following code:

 <%= f.select(:test_ids, options_from_collection_for_select(@tests, :id, :name, @promotion.test_ids), {}, {multiple: true, "data-validate" => true}) => 

I think options_from_collection_for_select , read the post post categories from this link may help you.

For check

I used validates_associated as shown below:

  validates_associated :tests 

To retrieve old attributes for a stored object

You can use reload for active recording as follows:

 1.9.2: 006> package => #<Package id: 1, name: "sample", cost: 3.3> 1.9.2: 007> package.test_ids => [1,2] 1.9.2: 007> package.test_ids = [1,2,3,4,5] => [1,2,3,4,5] 1.9.2: 007> package.reload => #<Package id: 1, name: "sample", cost: 3.3> 1.9.2: 008> package.test_ids => [1,2] 

Or you can check the validation of the package object, if it is false, reload it:

 unless package.valid? package.reload end 
+5
source

If you manually assigned test_ids in the controller, I would suggest updating the entire object using nested attributes. This assumes that params[:package][:test_ids] set to a list of test identifiers (with which Mohamed’s answer will help). Thus, the action of your controller will look something like this:

 def update package = Package.find(params[:id]) package.update_attributes params[:package] end 

This will update everything at once in the ActiveRecord / database transaction. This means that if the verification fails, all changes will be discarded, so it does not matter that the tests were saved. More info here .

In addition, I would recommend calling tests.size instead of test_ids.count , since the replacement will tend to generate a better query (or no need to access the database at all).

+3
source

Source: https://habr.com/ru/post/1205705/


All Articles