Reputation: 5407
I want to use Devise's current_user
helper in my model so I can save a Shop
's currency in a Dress
model using before_save
.
This won't work:
# Dress model
before_save :set_currency
def set_currency
self.currency = current_user.shop.currency
end
It does work in the controller:
def create
@dress = current_user.shop.dresses.create(params[:dress])
@dress.update_column(:currency, current_user.shop.currency)
end
but it seems inefficient since it's gonna do an UPDATE
after COMMIT
. Other users on StackOverflow said that current_user
should not be used in model. Is there any other way to access current_user
in model?
Upvotes: 0
Views: 2250
Reputation: 18784
I would recommend just dealing with setting them in the controllers, but...
If you don't mind violating MVC a bit, here's a way to do it:
# application_controller.rb
before_filter :set_current
def set_current
User.current = current_user
end
# app/models/user.rb
cattr_accessor :current
# app/models/dress.rb
before_save :set_currency
def set_currency
self.currency = User.current.shop.currency
end
Upvotes: 1
Reputation: 3187
One way is to pass the user as a parameter to the model method, and not use the before_save callback
# Dress model
def set_currency(user)
self.currency = user.shop.currency
end
Another way is to set the currency specifically. As the currency is a Dress' field, you could put a hidden field on your form with the current user currency, and that will be passed as a parameter to your create action, and will be saved transparently for you.
How to implement it:
# At your Dress form, in your View
<%= f.hidden_field :currency, :value => @user.shop.currency %>
# At your controller
def create
@user = current_user
end
Like this, you will not have to do anything to save the currency. It will be passed on the parameters to create the Dress, you just have to be sure that the currency
is an ActiveRecord field.
Usually, it is not good to attach to your model this kind of knowledge about the state of your application at a specific time. If you find yourself in a situation in which you are absolutely sure you need that kind of behavior, stop and ask yourself if that really makes sense.
In this example, I really feel (without knowing your application, there is) that the currency should be a hidden field in the form, because it is something that your model must have to exist, it is really a field, and therefore it makes sense to be passed with the model's parameters.
Best regards
Upvotes: 1
Reputation: 398
Use .build instead of .create in controller to set value to currency attribute of Dress model.
def create
@dress = current_user.shop.dresses.build(params[:dress])
@dress.currency = current_user.shop.currency
if @dress.save
.....
else
.....
end
end
Upvotes: 1