I got a task to access param values for creating new user.My controller code for create is
def newstudent
#student = Student.new(params)
puts "+++++++++++"
puts params.inspect
if #student.save
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #jtable }
end
end
end
But by doing this i had got some error in terminal.It shows like this
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: action, controller):
app/controllers/students_controller.rb:42:in `new'
app/controllers/students_controller.rb:42:in `newstudent'
Please help me to solve the problem?
This is my controller for add new student. By getting that error message you must reject controller and action using #student = Student.new(params.reject {|key,value| key =="controller" || key =="action"}) code.
def newstudent
#student = Student.new(params.reject {|key,value| key =="controller" || key =="action"})
if #student.save
#jtable = {'Result' => 'OK','Record' => #student.attributes}
else
#jtable = {'Result' => 'ERROR','Message'=>'Empty'}
end
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #jtable }
end
end
In rails 3.2.3 there is no mass assignment by default. You have to go your model and add attr_accessible :name, :position, :visible. Basically you have to add every attribute you want to mass assign.
class Student < ActiveRecord::Base
attr_accessible :name, :position, :visible
end
Your Student model should whitelist the attributes that can be mass-assigned using attr_accessible as in:
class Student < ActiveRecord::Base
attr_accessible :name
end
Related
i have problem when i have to declare value for one of parameters in my permit and out of post form values .
look at my code :
class QuoteController < ApplicationController
autocomplete :author, :name, :full => true
autocomplete :Category, :title, :full => true
def new
#quotes = Quote.new
end
def create
#quotes = Quote.new(quotesParams)
if #quotes.save
redirect_to root_url
else
redirect_to root_url
end
end
private
def quotesParams
params.require(:quote).permit(:text,:author_id, :category_id,
{:send_type => ["web"]},
{:user_id => [current_user.id])
end
end
but when i try to save in database send_type and user_id is null
Strong parameters is more about the structure of the parameters than the actual parameter values. So things like:
{ :send_type => ["web"] }
{ :user_id => [current_user.id] }
don't assign default values, they're specifying the structure of nested values in params.
I think you should handle your defaults in two places:
send_type should default to 'web' inside the model.
user_id should be required by the model but the controller should set the default (because that's who knows about current_user.
Something like this in your controller:
def create
#quotes = Quote.new(quotesParams) { |q| q.user_id = current_user.id }
#...
end
def quotesParams
params.require(:quote).permit(:text, :author_id, :category_id, :send_type)
end
and your model can default send_type to 'web' if the controller doesn't supply a value.
Try the following code for your controller:
class QuoteController < ApplicationController
autocomplete :author, :name, :full => true
autocomplete :Category, :title, :full => true
def new
#quotes = Quote.new
end
def create
#quotes = Quote.new(quotesParams)
#quotes.send_type = "web"
#quotes.user_id = current_user.id
if #quotes.save
redirect_to root_url
else
redirect_to root_url
end
end
private
def quotesParams
params.require(:quote).permit(:text, :author_id, :category_id)
end
end
I cannot seem to get to the bottom of where I am going wrong. My "order.rb" fields populate ok, but I can't get the "order_row" table values to populate. I just keep getting the following error in terminal(not worried about date for now, should be ok with that)...
Unpermitted parameters: date(i), order_row
Customer model(customer.rb)...
class Customer < ActiveRecord::Base
has_many :orders, dependent: :destroy
end
Order model(order.rb)...
class Order < ActiveRecord::Base
belongs_to :customer
has_many :order_rows, dependent: :destroy
accepts_nested_attributes_for :order_rows
end
Order_Row model(order_row.rb)
class OrderRow < ActiveRecord::Base
belongs_to :order
end
(orders_controller.rb)....
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to(#order, :notice => 'Order was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
private
def order_params
params.require(:order).permit(:customer_id, :date, :total,
:order_row_attributes => [:description, :quantity, :price, :order_id])
end
Form code on new.html.haml
= semantic_form_for #order do |f|
= f.input :customer_id, :as => :select, :collection => Hash[Customer.all.map{|c| [c.company,c.id]}]
= f.input :date
= f.fields_for :order_row do |ff|
= ff.input :description
= ff.input :quantity
= ff.input :price
= ff.hidden_field :order_id
= f.input :total
= f.action :submit, :as => :button
The problem is this line order_row_attributes.It should be order_rows_attributes. And with the date not being permitted,try changing the date attribute to some name like order_date.
This should work
private
def order_params
params.require(:order).permit(:customer_id, :order_date, :total,
:order_rows_attributes => [:description, :quantity, :price, :order_id])
end
I got it working by changing the new method to....
def new
#order = Order.new
#order.order_rows.build
end
So combination of this and Pavans answer did the trick.
I get a record not found exception using friendly_id 5.0 stable with Rails 4.0
Error:
Migration:
class AddSlugToUsers < ActiveRecord::Migration
def change
add_column :users, :slug, :string
add_index :users, :slug
end
end
Controller:
class UsersController < ApplicationController
load_and_authorize_resource
before_filter :authenticate_user!
def index
authorize! :index, #user, :message => 'Not authorized as an administrator.'
#users = User.all
end
def show
##user = User.find(params[:id])
#user = User.friendly.find(params[:id])
end
def update
authorize! :update, #user, :message => 'Not authorized as an administrator.'
#user = User.find(params[:id])
if #user.update_attributes(params[:user], :as => :admin)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
authorize! :destroy, #user, :message => 'Not authorized as an administrator.'
user = User.find(params[:id])
unless user == current_user
user.destroy
redirect_to users_path, :notice => "User deleted."
else
redirect_to users_path, :notice => "Can't delete yourself."
end
end
end
The Data:
INSERT INTO
users(id,email,encrypted_password,reset_password_token,reset_password_sent_at,remember_created_at,
sign_in_count,current_sign_in_at,last_sign_in_at,current_sign_in_ip,last_sign_in_ip,
created_at,updated_at,first_name,last_name,alias,bio,slug)
VALUES
(10,'me1#example.com','$2a$10$MYHASG','',null,null,0,null,null,'','',
Invalid Date,Invalid Date,'greek','god','tool','','tool');
It works if I put the ID into the url
http://0.0.0.0:3000/users/10
but does not work when using the slug
http://0.0.0.0:3000/users/tool
The quickest fix is to use the old 4-style finders as described in the readme by using the :finders addon.
Then you'll have friendly-id access via the "normal" find() method.
Example:
friendly_id :foo, use: [:slugged, :finders] # you can now do MyClass.find('bar')
Another hair-puller. AFter two days of fighting with this I cannot figure out what is wrong here.
Basically I have a form validation triggered by the model:
validates :user, :presence => true, :uniqueness => true
validates :email, :presence => true, :uniqueness => true, :on => :create
validates :passwordHash, :presence => true, :confirmation => true, :on => :create
The user not being empty works on the update form View:
= simple_form_for #user do |f|
= f.input :user
= f.input :locale
= f.input :localeLanguage, :label => 'Language', :as => :select, :collection => $language_array
= f.input :moderator
= f.input :email
= f.input :passwordHash, :label => 'Password'
But not on the new users View:
= simple_form_for #user do |f|
%table.table-condensed
%tr
%td
=f.input :user, :label => false, :placeholder => 'username'
%tr
%td
= f.input :passwordHash, :label => false, :placeholder => 'password'
%tr
%td
= f.input :email, :label => false, :placeholder => 'email'
%tr
%td
= f.submit "Create User", :class => 'btn btn-primary'
The only difference I can see between these views is that the first one has sessions created since a user has already logged in, the second one doesn't. But as far as I know this should not make a difference. Of course, the update form does have an actual #user object whereas in the new one it is empty. But I've seen Ryan Bates' railscast of a new user validation and he does pretty much the same thing.
What happens is the users#create action being invoked after submitting the form with empty values (which should not be possible). Of course I get an error because the passwordHash is empty.
I should point out that I'm not using any extra gems to aid in password confirmation (in the railscast, Bates uses bcrypt but I can't use it because we create the password hash a different way plus I think that's for the password confirmation magic only). In any case this should not affect the form validation should it?
Any theories or ideas are welcome here, I'm going crazy. I'm about to write some crappy javascript to do it by hand which would be awful and would probably take me a week, I don't do javascript ;)
Thanks.
Edit
Per Rachid's request, here are the new and create actions:
def new
#user = User.new
end
def create
#failsafe for failing form validation
unless params[:passwordHash].present?
redirect_to new_user_path, :notice => 'User or password cannot be blank'
else
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt)
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
redirect_to new_user_path, :notice => "User already exists, please pick another one"
end
end
end
Edit 2
I've rewritten the create method based on the first answer, but still getting an error:
def create
respond_to do |format|
if params[:passwordHash].present? && params[:user].present?
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt, :online_user => 1 )
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
The error is undefined method 'model_name' for NilClass:Class for this line:
= simple_form_for #user do |f|
Obviously the #user = User.new is not making it back to the form. At this point I'm a little confused as to how I should write the create method for it to work properly and show the error messages. But I feel I'm closer :)
#misha, here is the update controller action, it's just pretty standard scaffolding:
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
if session[:return_to]
format.html { redirect_to session[:return_to], :notice => 'User was successfully updated.' }
else
format.html { redirect_to users_path, :notice => 'User was successfully updated.' }
end
format.json { head :ok }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
First of all what you assume here is incorrect:
What happens is the users#create action being invoked after submitting
the form with empty values (which should not be possible). Of course I
get an error because the passwordHash is empty.
It is possible that users#create is invoked and actually it should happen. It is in the create action where you handle this stuff. I think your problem is the fact that you do a redirect if the #user is not saved. You should render the view again, so the error messages can be displayed.
So instead of:
redirect_to new_user_path, :notice => "User already exists, please pick another one"
Try:
render :action => 'new'
Edit based on your comment:
When validation fails Rails populates #user.errors automatically. You don't have to do anything in the controller (i.e. your create action)! All you have to do is display the errors in #user.errors in your view.
About the error you are getting now:
The reason you are getting the error is that #user is not set. You have to rewrite your create method to something like this:
def create
respond_to do |format|
if params[:user][:passwordHash].present?
password_and_salt = User.hash_password(params[:user][:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
end
#user = User.new(params[:user].merge({:passwordHash => hashed_password, :salt => user_salt, :online_user => 1}))
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
I'm using ActiveModel instead of ActiveRecord. And my model is:
class User
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
validates :name, :presence => true, :length => { :maximum => 50 }
validates :email, :presence => true,
:format =>
{
:with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
}
validates :password, :presence => true, :confirmation => true,
:length =>
{
:within => 6..40
}
attr_accessor :name, :email, :password, :password_confirmation
def initialize(attributes = {})
#name = attributes[:name]
#email = attributes[:email]
#password = attributes[:password]
#password_confirmation = attributes[:password_confirmation]
end
def persisted?
false
end
def save
# createUser calls RESTful HTTP server and gets back JSON in http response's body
response = createUser(self.name, self.email, self.password)
end
end
And in my users_controller.rb below when I try to process this response returned by save method above, it messes up my model's validations for password and password_confirmation.
def create
#user = User.new(params[:user])
response = #user.save
parsed_response_body = ActiveSupport::JSON.decode(response.body)
# response body I have is {"ok":"ok message"} OR {"error":"error message"}
message = parsed_response_body["error"]
if #user.valid? && message.nil?
flash[:success] = message
redirect_to signup_path
else
#user.password = ""
#user.password_confirmation = ""
flash[:error] = message
render :action => 'new'
end
end
And below is controller code that doesn't break the validations; where #user.save in this case is returning true.
def create
#user = User.new(params[:user])
if #user.valid? && #user.save
flash[:success] = "Done"
redirect_to signup_path
else
#user.password = ""
#user.password_confirmation = ""
flash[:error] = "Not Done"
render :action => 'new'
end
end
I'd be thankful if someone can help me with this..
It looks to me like you need to call super in save or it won't actually try to validate:
def save
super
# createUser calls RESTful HTTP server and gets back JSON in http response's body
response = createUser(self.name, self.email, self.password)
end