I am totally new in the Ruby on Rails. I have tried to show an message while register. Please check my controller and view code -
users_controller.rb
class UsersController < ApplicationController
#before_action :set_user, only: [:show, :edit, :update, :destroy, :success]
def login
render layout: false
end
def register
render layout: false
#user = User.new
end
def create_register
#user = User.new(create_user_params)
#raise #user.inspect
respond_to do |format|
if #user.save
format.html { redirect_to #users, notice: 'Registration was successfully created.' }
format.json { render :success, status: :created, location: #users }
else
format.html { render :register }
format.json { render json: #ruby_win_source.errors, status: :unprocessable_entity }
end
end
end
def success
raise #user.inspect
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :username, :email, :password, :image, :dob, :photo, :address)
end
end
register.html.erb
<%= form_tag(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
routes.rb
get 'register' => 'users#register'
post 'register' => 'users#create_register'
URL - http://localhost:3000/register
While I am loading this page I got this error message -
I searched in google and getting some same issue link. Follow step but my problem still not resolved. Please help me :(
The 2 lines in your register method are reversed. Try this:
def register
#user = User.new
render layout: false
end
In the create_register method you create a new user calling
#user = User.new(create_user_params)
but your strong params method is named user_params. Try changing the above line to
#user = User.new(user_params)
You are trying to run the method errors on a nil class. Very common issue when doing Rails. This line
<%= form_tag(#user) do |f| %>
<% if #user.errors.any? %>
is looking for a #user object. You did try to declare one here:
def register
render layout: false
#user = User.new
end
But based on the error I'm going to presume it failed. Not seeing a migration for the user table I'm guessing you didn't create one? To create a new User object for an active record class you need to run a migration against the database so that there is a table to work with.
http://guides.rubyonrails.org/active_record_migrations.html
I am also not seeing a model here. To user User.new you also need a model.
http://guides.rubyonrails.org/active_record_basics.html
Now there is one other tool that will making working in Rails much, much easier for you.
http://pryrepl.org/
Coolest tool ever. simply install the pry gem, require pry and place a newline with binding.pry wherever you need to pry into the code and you can play around directly with the code. For this instance I would do it like this.
def register
render layout: false
require `pry`; binding.pry;
#user = User.new
end
Then go to the terminal you are running your server and you are inside the code. Then try the failing part of the code. #user = User.new It will give you a much more illuminating error message.
Related
In my index page I am trying to create a modal that contains a form so that users can create users on the index page. I am using devise to create these users.
However, when I try to create the form for this in the modal, I get this error.
First argument in form cannot contain nil or be empty
<%= form_for #user, html: { multipart: true } do |form| %>
...
<% end %>
Here is my controller:
class UsersController < ApplicationController
before_action :find_account, only: [:index, :new, :create]
def index
if params[:email].present?
#users = User.where(email: params[:email]).first
else
#users = User.all
end
respond_with #users
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to root_url, notice: 'User was sucessfully created' }
else
format.html { render :new }
end
end
end
private
def user_params
params.require(:user).permit(:email, :first_name, :last_name, :password)
end
def find_account
#account ||= Account.find(params[:account_id])
end
end
The user is a nested route because it belongs to an account:
new_account_user GET /accounts/:account_id/users/new(.:format) users#new
Does anybody know why I am getting this error? Since I am creating the #user variable in my controller and finding the account_id in the before_action I am not sure what the problem is.
Update:
If I implement this feature in another form that is working it gives the same error. Possibly something having to do with this not being on the correct action page?
You defined #user but using #material in form and of course #material is nil -> throw the errors.
If the user belongs to account, so the form should be:
<%= form_for [#account, #user], html: { multipart: true } do |form| %>
...
<% end %>
If the user is independent, so the form should be:
<%= form_for #user, html: { multipart: true } do |form| %>
...
<% end %>
I'm running into a problem when trying to create a new object using nested resources in Rails. My routing is set up as:
resources :coins do
resources :questions
end
When I attempt to create a new question, it does not save. I'm redirected to the 'questions' page and the form from the 'new' page including everything that was typed into it remains on the page (rather than the list of questions that are supposed to be there when it saves). My controller is as follows:
class QuestionsController < ApplicationController
before_action :find_question, only: [:show]
before_action :find_coin
before_action :authenticate_user!, except: [:index, :show]
def index
#questions = Question.where(coin_id: #coin.id).order("created_at DESC")
end
def show
end
def new
#coin
#question = current_user.questions.build
end
def create
#question = current_user.questions.build(question_params)
if #question.save
redirect_to coin_question(#question.coin_id, #question.id)
else
render 'new'
end
end
private
def find_question
#question = Question.find(params[:id])
end
def find_coin
#coin = Coin.find(params[:coin_id])
end
def question_params
params.require(:question).permit(:content, :ques_num, :coin_id)
end
end
My 'new' page then displays the following form:
<%= simple_form_for #question, url: coin_questions_path(#coin.id) do |f| %>
<%= f.input :ques_num %>
<%= f.input :content %>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
This is my first time using nested resources and its tripping me up a little bit. I really appreciate any assistance here.
Your create action is failing and so it's executing the else statement which is just rendering back your form with the data you entered. The easiest thing to do is to just check out the log file and see why the save it being blocked.
go to /log/development.log and if you're using a mac press Command and the down arrow which will bring you all the way to the bottom of the file.
Also you may want to check out your model validations. If you don't have flash setup or aren't outputting the errors to your view a validation may be causing the form not to save and you wouldn't see the errors.
you could add some error handling to your view like this
<%= form_with(model: question, local: true) do |form| %>
<% if question.errors.any? %>
<div id="error_explanation">
<h2 class="text-danger"><%= pluralize(question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul class="text-danger">
<% question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
for your controller try
def create
#question = Question.new(question_params)
if #question.save
flash[:success] = "question created successfully!"
redirect_to question_url(#question.id)
else
render 'new'
end
end
I think there will be error to create question.
if #question.save
redirect_to coin_question(#question.coin_id, #question.id)
else
render 'new'
end
So if record have any error to save it will redirect to new form.
Just use following code to know what is the errors to creating question
def create
#question = current_user.questions.build(question_params)
if #question.save
flash[:notice] = 'Question created'
redirect_to coin_question(#question.coin_id, #question.id)
else
flash[:notice] = 'Some error here!'
render 'new'
end
end
You need to setup flash to show flash error.
I have looked through the other answers provided on StackOverflow, and none of them answered my question. Here is what is happening with my code.
Error
undefined method `update' for nil:NilClass
Problem:
It looks like the param id is not being sent to the controller from the form as they show up as nil in the console using byebug.
console readout:
(byebug) params[:id]
nil
(byebug) #support
nil
(byebug) params[:title]
nil
(byebug) params[:support]
<ActionController::Parameters {"title"=>"Test", "subtitle"=>"testing",
"website"=>"www.test.com", "type_of_support"=>"", "description"=>""}
permitted: false>
(byebug) params[:support][:id]
nil
(byebug) params[:support][:title]
"Test"
I do not believe that the problem is with the form as it is the same form partial used for the new/create action and the params are sent to the controller then and the object is created (though in that case there is no id, since it is generated when creating the object, not passed from the form).
You can see in my code below that the route for PATCH is just 'support' without the :id param. If I try to add that to the route, I get an error stating that there is no route matching 'support/'. So, I have to take away the :id param in the route for it to pass the information to the controller.
I am at a loss here. How do I pass the :id to the controller? How does rails do this? Before I manually change the routes, the automatic routes from resources :supports includes an :id param for the PATCH route and it works. What am I doing wrong that it won't allow me to add that to the route?
Code:
config/routes.rb
get 'support', as: 'supports', to: 'supports#index'
post 'support', to: 'supports#create'
get 'support/new', as: 'new_support', to: 'supports#new'
get 'support/:id/edit', as: 'edit_support', to: 'supports#edit'
get 'support/:title', as: 'support_page', to: 'supports#show'
patch 'support/', to: 'supports#update'
put 'support/:id', to: 'supports#update'
delete 'supports/:id', to: 'supports#destroy'
Results this for rake routes:
supports GET /support(.:format) supports#index
support POST /support(.:format) supports#create
new_support GET /support/new(.:format) supports#new
edit_support GET /support/:id/edit(.:format) supports#edit
support_page GET /support/:title(.:format) supports#show
PATCH /support(.:format) supports#update
PUT /support/:id(.:format) supports#update
DELETE /supports/:id(.:format) supports#destroy
app/controllers/supports_controllers.rb
class SupportsController < ApplicationController
before_action :set_support_by_title, only: [:show]
before_action :set_support_by_id, only: [:edit, :update, :destroy]
def index
#supports = Support.all
end
def show
end
def new
#support = Support.new
end
def edit
end
def create
#support = Support.new(support_params)
respond_to do |format|
if #support.save
format.html { redirect_to #support,
notice: 'Support was successfully created.' }
else
format.html { render :new }
end
end
end
def update
# byebug
respond_to do |format|
if #support.update(support_params)
format.html { redirect_to #support,
notice: 'Support was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
#support.destroy
respond_to do |format|
format.html { redirect_to supports_url,
notice: 'Support was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_support_by_title
#support = Support.find_by(title: params[:title])
# byebug
end
def set_support_by_id
#support = Support.find(params[:id])
# byebug
end
# Never trust parameters from the scary internet,
# only allow the white list through.
def support_params
params.require(:support).permit(:title,
:subtitle,
:website,
:type_of_support,
:description)
end
end
app/views/supports/edit.html.erb
<h1>Editing Support</h1>
<%= render 'form', support: #support %>
<%= link_to 'Show', support_page_path(#support.title) %> |
<%= link_to 'Back', supports_path %>
app/views/supports/_form.html.erb
<%= form_with(model: support, local: true) do |form| %>
<% if support.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(support.errors.count, "error") %>
prohibited this support from being saved:
</h2>
<ul>
<% support.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
Title:
<%= form.text_field :title, id: :support_title %>
</div>
<div class="field">
Subtitle:
<%= form.text_field :subtitle, id: :support_subtitle %>
</div>
<div class="field">
Website:
<%= form.text_field :website, id: :support_website %>
</div>
<div class="field">
Type of Support:
<%= form.text_field :type_of_support, id: :support_type %>
</div>
<div class="field">
Description:
<%= form.text_area :description, id: :support_description %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
While writing this question, I thought of something and tried it. And it worked. Instead of re-writing all of the routes myself, I wrote only 2 and used the resources :supports, except: [:index, :show] to have rails generate the others. This solved my issue.
Explanation
I knew that something was going on behind the scenes that I did not understand. The entire process worked fine before I started to change the routes. So, something in there was incorrect. (I still don't know what it is and how to change it.)
The only two routes that I really want to be changed are the two that users see. I don't care about how the routes look in the admin backend. So, that meant that I only needed to change the routes for index and show to be SEO friendly and look better in the browser. So, to do that I wrote the routes like this:
config/routes.rb
resources :supports, except: [:index, :show]
get 'support', as: 'support_index', to: 'supports#index'
get 'support/:title', as: 'support_page', to: 'supports#show'
This then created all of the new, create, edit, update, destroy routes for me. After doing this, this is how my routes now look:
supports POST /supports(.:format) supports#create
new_support GET /supports/new(.:format) supports#new
edit_support GET /supports/:id/edit(.:format) supports#edit
support PATCH /supports/:id(.:format) supports#update
PUT /supports/:id(.:format) supports#update
DELETE /supports/:id(.:format) supports#destroy
support_index GET /support(.:format) supports#index
support_page GET /support/:title(.:format) supports#show
As you can see, the PATCH route is now getting the param :id to be able to update the record.
Now, I just had to change a few of the redirects in the controller after create, update and destroy like this:
def create
#support = Support.new(support_params)
respond_to do |format|
if #support.save
format.html { redirect_to support_page_path(title: #support.title),
notice: 'Support was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if #support.update(support_params)
format.html { redirect_to support_page_path(title: #support.title),
notice: 'Support was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
#support.destroy
respond_to do |format|
format.html { redirect_to support_index_path,
notice: 'Support was successfully deleted.' }
end
end
These redirect_to statements now match the routes that I generated for index and show.
And now everything works.
So, problem solved, though I still don't know what I was doing wrong before. Any light that can be shed would be appreciated.
I've newly upgraded to rails 4.0.1
Simple enough experiment to test the new strong params:
class StatusesController < ApplicationController
before_action :set_status, only: [:show, :edit, :update, :destroy]
# GET /statuses
# yersh GET /statuses.json
def index
#statuses = Status.all
end
# GET /statuses/1
# GET /statuses/1.json
def show
# GET thingy
end
# GET /statuses/sdfnew
def new
#status = Status.new
end
# GET /statuses/1/edit
def edit
end
# POST /statuses
# POST /statuses.json
def create
#status = Status.new(status_params)
respond_to do |format|
if #status.save
format.html { redirect_to #status, notice: 'Status was successfully created.' }
format.json { render action: 'show', status: :created, location: #status }
else
format.html { render action: 'new' }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /statuses/1
# PATCH/PUT /statuses/1.json
def update
respond_to do |format|
if #status.update(status_params)
format.html { redirect_to #status, notice: 'Status was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# DELETE /statuses/1
# DELETE /statuses/1.json
def destroy
#status.destroy
respond_to do |format|
format.html { redirect_to statuses_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_status
#status = Status.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def status_params
params.require(:status).permit(:nothing)
end
As you can see, the only parameter I have whitelisted is something called 'nothing'. So here's my new status view and form:
<%= simple_form_for(#status, html: { class: "form-group"}) do |f| %>
<% if #status.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#status.errors.count, "error") %> prohibited this status from being saved:</h2>
<ul>
<% #status.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.input :content, class: "form-control" %><br>
</div>
<div class="form-actions">
<%= f.button :submit, class: "btn btn-success" %>
</div>
<% end %>
As you can see, it has one input, for a parameter called content. I enter data and submit the form, and I am routed to get a flash saying 'Status was successfully created.', and routed to the status. Now, the content field is empty on this status (note the second column from the left):
24||2013-11-29 16:34:01.389499|2013-11-29 16:34:01.389499|
So this means the status_params method did do its job of stopping 'content' from being written to the database, but the damn thing is still created, albeit with an empty 'content' entry. I want a mass-assignment error, like in the good old days of attr_accessor. How can I get this behavior? I wish to stop a status being created if one of its attributes is not white listed?
Also, just venting here, but does anyone else think this whitelist strong params thing is utterly, utterly, utterly vile? Loved attr_access to bits, it was well organised (models contained everything to do with models, like they should), it was easy and not fiddly, and you could glance at your model files to see what attributes they have. No, when I want to verify what attributes a model has I need to fire up my rails console and run
Status.column_names
Urgh it's all just so hideous. Is there a chance it could be changed back? For nutjobs who want to have their model behavior in their controllers there should be gem for this. To overhaul rails like this, and not add backward functionality add the very least, is just rude.
This question is still open! I understand this behaviour does not happen in production, so that's great, but I'd still like to get a mass-assignment error for debugging purposes in the development environment, as well as the console message!
According to this source you can configure this behavior:
initializer "strong_parameters.config", :before => "action_controller.set_configs" do |app|
ActionController::Parameters.action_on_unpermitted_parameters = app.config.action_controller.delete(:action_on_unpermitted_parameters) do
(Rails.env.test? || Rails.env.development?) ? :log : false
end
end
Try setting in config/environments/development.rb:
config.action_controller.action_on_unpermitted_parameters = false
I haven't tried it but there definitely should be some way.
I've been trying to edit the default scaffolding, and have been thus far quite successful. However, this little puzzle has managed to boggle me, as even reverting the file to it's original state isn't working. It's throwing up a "undefined method `model_name' for NilClass:Class" as the title suggests.
New Action In User Controller:
def new
if #current_user
redirect_to(action: 'home')
else
#user = User.new
end
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
_form.html.erb beginning
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
Any help would be appreciated!
In the case when #current_user is set, your new action doesn't stop executing after the redirect_to. Execution proceeds to the respond_to block, which attempts to render the page without setting #user, resulting in the error you're getting.
Possible solutions:
Use a before filter—Execution of the current action is halted if a before filter triggers a redirect. This is standard Rails practice.
before_filter :check_for_current_user, only: [:new]
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
protected
def check_for_current_user
redirect_to(action: 'home') if #current_user
end
Just return early.
def new
if #current_user
redirect_to(action: 'home') and return
end
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
Cite: http://excid3.com/blog/execution-after-redirect-vulnerability