Rails: Has and belongs to many (HABTM) -- create association without creating other records
You can do this in a two-step procedure, using the very useful find_or_create
method. find_or_create
will first attempt to find a record, and if it doesn't exist, create it. Something like this should do the trick:
core_value = CoreValue.find_or_create_by_value(v, :created_by => current_user.id)current_user.core_values << core_value
Some notes:
- The first line will find or create the value
v
. If it doesn't exist and is created, it will set thecreated_by
tocurrent_user.id
. - There's no need to do
User.find(current_user.id)
, as that would return the same object ascurrent_user
. current_user.core_values
is an array, and you can easily add another value to it by using<<
.
For brevity, the following would be the same as the code example above:
current_user.core_values << CoreValue.find_or_create_by_value(v, :created_by => current_user.id)
Add a method in your user model:
class User < ActiveRecord::Base def assign_core_value(v) core_values.find_by_name(v) || ( self.core_values << CoreValue.find_or_create_by_name(:name => v, :created_by => self)).last endend
The assign_core_value
method meets requirement 1,2 and returns the core value assigned to the user (with the given name).
Now you can do the following:
current_user.assign_core_value(v)
Note 1
Method logic is as follows:
1) Checks if the CoreValue is already associated with the user. If so no action is taken, core value is returned.
2) Checks if the CoreValue with the given name exists. If not creates the CoreValue. Associates the core value(created/found) with the user.
Active Record already gives you a method. In your case,
val = CoreValue.find_by_value(v)current_user.core_values << val
You can also pass a number of objects at ones this way. All the associations will be created
Check this for more information