Why does my controller not set an attribute in the create action of my User's controller? - Rails 3
This is the create action:
def create
@user = User.new(params[:user])
@user.coupon_code = params[:xcode]
respond_to do |format|
if @user.save
UserMailer.welcome_email(@user).deliver
format.html { redirect_to(@user, :notice => 'User was successfully created.') }
format.xml { render :xml => @user, :status => :created, :location => @user }
else
format.html { render :action => "new" }
format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
end
end
end
Basically what I want to do is before the user is saved, I want to set the attribute coupon_code
of that newly created User, to be the string sent in via the params[:xcode]
.
I know the value is in my params, as can be seen in the log output:
Started POST "/users" for 127.0.0.1 at 2011-08-24 17:33:07 -0500
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Jp2GHxnuVOVnI/sfr1CB4EQ9URCTJynv/2Ek4AiU8Lg=", "user"=>{"username"=>"test.user", "first_name"=>"Testing", "last_name"=>"User", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "email"=>"testuser@abc.com", "plan_id"=>"1"}, "xcode"=>"testusercoupon", "commit"=>"Register"}
nil
SQL (0.2ms) SELECT 1 FROM "users" WHERE (LOWER("users"."email") = LOWER('testuser@abc.com')) LIMIT 1
Plan Load (0.3ms) SELECT "plans".* FROM "plans" WHERE "plans"."id" = 1 ORDER BY id LIMIT 1
SQL (0.2ms) SELECT 1 FROM "users" WHERE (LOWER("users"."username") = LOWER('test.user')) LIMIT 1
CACHE (0.0ms) SELECT 1 FROM "users" WHERE (LOWER("users"."email") = LOWER('testuser@abc.com')) LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = 'b2GnABnQ1on-K_2Dwf3M' LIMIT 1
Role Load (0.2ms) SELECT "roles".* FROM "roles" WHERE "roles"."name" = 'designer' LIMIT 1
AREL (0.4ms) INSERT INTO "users" ("email", "encrypted_password", "password_salt", "reset_password_token", "remember_token", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "username", "first_name", "last_name", "created_at", "updated_at", "invitation_token", "invitation_sent_at", "plan_id", "current_state", "confirmation_token", "confirmed_at", "confirmation_sent_at", "space_used", "failed_attempts", "unlock_token", "locked_at", "trial_end_date", "active_subscription", "customer_id", "coupon_code") VALUES ('testuser@abc.com', '$2a$10$DerQxksUpQhoD.QheuxYneNGo7Nd2lHIzbtJrpCnd3lRTY/NFH9RK', '$2a$10$DerQxksUpQhoD.QheuxYne', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'test.user', 'Testing', 'User', '2011-08-24 22:33:07.660722', '2011-08-24 22:33:07.660722', NULL, NULL, 1, NULL, 'b2GnABnQ1on-K_2Dwf3M', NULL, '2011-08-24 22:33:07.542240', 0, 0, NULL, NULL, '2011-09-07', NULL, NULL, NULL)
Rendered devise/mailer/confirmation_instructions.html.erb (1.5ms)
But, as you can see in the AREL statement NULL
is inserted into the db.
How do I get the params value into the db?
P.S. I tried doing it as a callback in the model (e.g. before_save
), but the problem is getting the value from the form field. As far as I understand it, I can't pass data from the form field (i.e. params[:xcode]
) directly to my model. I have to do it in the controller...so that's why I have done it like this. Help!
Edit 1:
User model, specifically the before_filters
class User < ActiveRecord::Base
acts_as_voter
devise :database_authenticatable, :confirmable, :registerable, :timeoutable,
:recoverable, :rememberable, :trackable, :validatable, :invitable, :lockable
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :first_name, :last_name, :plan_id
has_friendly_id :username, :use_slug => true, :strip_non_ascii => true
validates_presence_of :username, :email, :plan
validates_uniqueness_of :username, :email, :case_sensitive => false
before_create :assign_default_role
after_validation :set_trial_end
def set_trial_end
plan = self.plan
end_of_trial = Date.today + self.plan.trial_duration.days
self.trial_end_date = end_of_trial.to_date
end
Edit 2: Here is the form element that sends back params[:xcode]
<div class="settings_form">
<% @user.plan_id = params[:plan_id] %>
<%= devise_error_messages! %><br />
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<% if !params[:prom开发者_JS百科o] %>
<%= f.collection_select :plan_id, @plan, :id, :display_name, :prompt => "Choose yourself up a real nice plan" %><br />
<% end %>
<%= f.text_field :username, :placeholder => "Desired Username" %><br />
<%= f.text_field :first_name, :placeholder => "First Name" %><br />
<%= f.text_field :last_name, :placeholder => "Last Name" %><br />
<%= f.password_field :password, :placeholder => "Password" %><br />
<%= f.password_field :password_confirmation, :placeholder => "Password" %><br />
<%= f.text_field :email, :placeholder => "Email Address" %><br />
<% if params[:promo] %>
<%= text_field_tag "xcode", :placeholder => "Coupon Code" %><br />
<%= hidden_field_tag 'user[plan_id]', "1" %>
<% end %>
<div class="settings_button">
<%= f.submit "Sign in", :id => "register", :value => "Register", :class => "pill button" %>
</div>
<% end %>
</div>
Have you tried changing you ERB view code so that
<%= text_field_tag "xcode", :placeholder => "Coupon Code" %><br />
becomes
<%= text_field_tag "user[coupon_code]", :placeholder => "Coupon Code" %><br />
and then removing the controller action to assign this value? In fact, you probably could even replace it with
<%= f.text_field :coupon_code, :placeholder => "Coupon Code" %>
As long as it is within an ERB if statement it will only show up under the appropriate conditions, and your controller will not have to rename the parameter.
精彩评论