I'm using Rails 3.2.17
trying to access two virtual attributes (expiration_amount
& expiration_format
) in a model but nothing I've tried allows me to access them.
Everything else seems to update correctly, however in my logs the virtual attributes always come up blank.
EDIT I added both :expiration_amount
:expiration_format
to attr_accessible
as suggested but it's still not working. They both come up blank. One thing I did notice was that the logger calls were happening after it hits the DB. Is before_update
not the correct filter for this?
EDIT 2 Is it possible Devise
is preventing the virtual attributes from being accessed?
EDIT 3 I just decided to kick it off from the controller (which is working), though I'm still curious as to why I couldn't access those virtual attributes in the model.
Working Controller action (Update method)
@user.set_expiration(params[:expiration_amount].to_i, params[:expiration_format])
Working Model method
def set_expiration(amount, format)
if defined?(amount) && defined?(format)
case format
when "hours"
self.expiration = amount.hours.from_now
when "days"
self.expiration = amount.days.from_now
when "weeks"
self.expiration = amount.weeks.from_now
else
self.expiration = amount.hours.from_now
end
end
end
---ORIGINAL CODE---
User.rb
class User < ActiveRecord::Base
attr_accessible :email,
:password,
:password_confirmation,
:remember_me,
:first_name,
:last_name,
:company,
:phone,
:expiration,
:expiration_amount,
:expiration_format
attr_accessor :expiration_amount,
:expiration_format
before_update :set_expiration
def set_expiration
logger.debug "DEBUG - expiration_amount: #{expiration_amount}"
logger.debug "DEBUG - expiration_format: #{expiration_format}"
if expiration_amount && expiration_format
case expiration_format
when "hours"
self.expiration = expiration_amount.hours.from_now
when "days"
self.expiration = expiration_amount.days.from_now
when "weeks"
self.expiration = expiration_amount.weeks.from_now
else
self.expiration = expiration_amount.hours.from_now
end
end
end
end
form
= form_for(resource, :as => resource_name, :url => admins_user_update_path(resource), :html => { :method => :put }) do |f|
= devise_error_messages!
%fieldset{id: "edit-user-account"}
%legend
Set User Access
.field.required
%label
"Allow access for "
= select_tag "expiration_amount", options_for_select(expiration_amount, 3)
= select_tag "expiration_format", options_for_select(expiration_format, "days")
%span.instructions
From Now
.field
= f.submit "Grant Access"
logs
Parameters: {"utf8"=>"✓", "authenticity_token"=>"xxx=", "expiration_amount"=>"3", "expiration_format"=>"days", "commit"=>"Grant Access", "id"=>"5"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", "5"]]
Admin Load (0.4ms) SELECT "admins".* FROM "admins" WHERE "admins"."id" = 1 LIMIT 1
(0.3ms) BEGIN
DEBUG - expiration_amount:
DEBUG - expiration_format:
(0.3ms) COMMIT
Redirected to http://localhost:8080/admins/users
I finally figured out what the problem was! Because I was using select_tags
with stings it wasn't naming them correctly, so:
= select_tag "expiration_amount", options_for_select(expiration_amount, 3)
= select_tag "expiration_format", options_for_select(expiration_format, "days")
was rendering as:
<select id="expiration_amount" name="expiration_amount">
<select id="expiration_format" name="expiration_format">
But what they needed to be for the model to pick them up is:
= f.select :expiration_amount, options_for_select(expiration_amount, 3)
= f.select :expiration_format, options_for_select(expiration_format, "days")
<select id="user_expiration_amount" name="user[expiration_amount]">
<select id="user_expiration_format" name="user[expiration_format]">
After that I was able to do everything in the model as opposed to the controller.
model method
before_update :set_expiration
def set_expiration
logger.debug "DEBUG @ User - expiration_amount: #{expiration_amount}"
logger.debug "DEBUG @ User - expiration_format: #{expiration_format}"
if defined?(expiration_amount) && defined?(expiration_format)
amount = expiration_amount.to_i
case expiration_format
when "hours"
self.expiration = amount.hours.from_now
when "days"
self.expiration = amount.days.from_now
when "weeks"
self.expiration = amount.weeks.from_now
else
self.expiration = 0.hours.from_now
end
end
end