hsym
hsym

Reputation: 5407

How do I use current_user in model?

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

Answers (3)

Unixmonkey
Unixmonkey

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

Castilho
Castilho

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

Georgi
Georgi

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

Related Questions