I am trying to have a login form in my rails applicaiton but getting an error like
NameError in AuthController#login
uninitialized constant AuthController::User
Here is my view
<%= form_for #users, do |f| %>
<%= f.text_field :name, placeholder: 'Username' %>
<%= end %>
My controller is
def login
##users = User.all I
end
When you use any variable in your view, you must assign/define it in action def of controller page.
You can use for an empty value-
def login
#user = User.new
.......
end
As for login you have no pre assigned values (which is used for edit form), you must use an empty object.
In your controller you would have to define the user and then your form will be called for that particular object:
def login
#user = User.new
.....
end
<%= form_for #user, do |f| %> ....
Related
I'm working on messaging system between User and AdminUser. The User part is ready now I'm struggling how to allow Admin to send a reply to a conversation started by a User, inside of ActiveAdmin.
Code below:
# app/admin/conversations.rb
ActiveAdmin.register Conversation do
decorate_with ConversationDecorator
# ...
controller do
def show
super
#message = #conversation.messages.build
end
end
end
app/views/admin/conversations/_show.html.erb
# ...
<%= form_for [#conversation, #message] do |f| %>
<%= f.text_area :body %>
<%= f.text_field :messageable_id, value: current_user.id, type: "hidden" %>
<%= f.text_field :messageable_type, value: "#{current_user.class.name}", type: "hidden" %>
<%= f.submit "Send Reply" %>
<% end %>
<% end %>
Which gives me an error:
First argument in form cannot contain nil or be empty
Extracted source (around line #51):
51 <%= form_for [#conversation, #message] do |f| %>
When I tried to debug it turned out #message = nil inside of _show.html.erb. How is that possible if I defined #message inside of ActiveAdmin controller ?
[EDIT]
In case you're curious, ConversationController below:
class ConversationsController < ApplicationController
before_action :authenticate_user!
def index
#admins = AdminUser.all
#conversations = Conversation.all
end
def new
#conversation = Conversation.new
#conversation.messages.build
end
def create
#conversation = Conversation.create!(conversation_params)
redirect_to conversation_messages_path(#conversation)
end
end
#routes
resources :conversations do
resources :messages
end
Normally you set up instance variables in your controller, and then Rails later does an implicit render of the view once the controller method completes.
However, it is possible to do an explicit render of the view, by calling something like render action: or render template: while the controller method is running, and presumably this is happening within the call to super.
See the Layout and Rendering Rails Guide for more information.
You'll need to move the assignment to be before the call to super.
You may also need to replace #conversation with resource in the ActiveAdmin controller (this is an ActiveAdmin/InheritedResources gem thing).
I've been told that I should not create my Quiz object before my quiz is completed; A user could go to the quiz page, not complete it, and there would be an 'unused' quiz sitting on the database. I can see the logic of that.
I CAN'T see how my quiz is supposed to work without being passed a #quiz object. Here's my QuizzesController, which, when the quiz is needed, gets routed to the 'new' action:
class QuizzesController < ApplicationController
def index
end
def new
#user = current_user
#quiz = Quiz.create(user_id: current_user.id)
end
def create
#results = Quiz.where(user_id: current_user.id).last
redirect_to results_path
end
end
At the moment, you can see that I'm coding the actions as simply as possible. Later, in the 'new' action, I'll add a test to see if the current_user has done the quiz and, if so, redirect to results_path.
Here is my form partial which is rendered as part of quizzes/new.html.erb:
<%= form_for(#quiz) do |f| %>
<p>
<%= f.check_box(:answer1) %>
<%= f.check_box(:answer2) %>
<%= f.check_box(:answer3) %>
<%= f.check_box(:answer4) %>
<%= f.check_box(:answer5) %>
<%= f.check_box(:answer6) %>
<%= f.check_box(:answer7) %>
<%= f.check_box(:answer8) %>
</p>
<p>
<%= f.submit("Get my results!") %>
</p>
<% end %>
Once again, the quiz is very simple while I figure out what's going on.
But I'd like to know, if the #quiz object is not created in the 'new' action, what would I pass into form_for to build the form?
You can instantiate a Quiz object without saving it to the database:
def new
#user = current_user
#quiz = Quiz.new(user_id: current_user.id)
end
The generally used sequence of requests/actions is the following:
The new action just initializes the model's instance with default values, and renders the record with empty fields, usually in a edit view.
def new
#quiz = Quiz.new(user_id: current_user.id)
render :edit
end
create action create the record, and after the create action you should render either the view of the newly created record by redirection to show action with the same view, or to redirect to a new action, in case you are creating a sequence of the same instances of a model.
def create
#quiz = Quiz.create(params)
render :show # or redirect_to :new
end
edit action is to prepare edit fields, is it renders edit view with filled-in fields.
def edit
#quiz = Quiz.where(id: params[:id]).first
end
update action updates the record with values set in edit view, then it renders the show view on the current record.
def update
#quiz = Quiz.update(params)
render :show
end
show action just shows the model's found out with stored in the DB values, then it renders show view with filled-in fields.
def show
#quiz = Quiz.where(id: params[:id]).first
end
So in your show.erb view you get rendering the newly built, or found out instance of Quiz:
<%= form_for #quiz, url: {action: "create"} do |f| %>
<p>
<%= f.check_box(:answer1) %>
<%# ... %>
</p>
<p>
<%= f.submit "Create Quiz" %>
</p>
<% end %>
But I prefer simple-form gem:
<%= simple_form_for #quiz do |f| %>
<%= f.input :answer1, as: :boolean, checked_value: true, unchecked_value: false %>
<%= f.button :submit %>
<% end %>
I am using the Gem Devise for users in my application. I added the role attribute within users that is set to nil. After I sign in, within the application controller I have a redirect that goes to a custom action within the users controller and view called binary_selection if current_user.role = nil. The code is below
application_controller.rb:
def after_sign_in_path_for(resource)
if current_user.role.nil? ## temporary solution
#update_path(resource)
binary_selection_path(resource)
else
root_path(resource)
end
end
users_controller.rb:
def binary_selection
#user = current_user
respond_to do |format|
if #user.update_attributes(params[:user][:role])
format.html { redirect_to root_url, notice: "#{#user.name} was updated." }
else
format.html { render action: "edit" }
end
end
end
views/users/binary_selection.html.erb:
<%= form_for #user, url: binary_selection_path(#user), html: { method: :patch } do |f|
%><%= current_user %>
<div class = "form-group">
<%= f.label :role %>
<%= f.text_field :role, class: 'form-control', placeholder: "Enter wiki title", id: 'wiki_title' %>
</div>
<div class = "form-group">
<%= f.submit class: 'btn btn-success' ,id: 'wiki_submit' %>
</div>
<% end %>
config/routes.rb:
Rails.application.routes.draw do
devise_for :users
get "/users" => "users#binary_selection", as: 'binary_selection'
resources :users
end
When I get redirected to the binary_selection view I get this error:
NoMethodError in UsersController#binary_selection
undefined method `[]' for nil:NilClass
where it highlights this line within the users controller:
if #user.update_attributes(params[:user][:role])
I also noticed it has this for the params on the error page:
{"format"=>"13"}
You redirect your user after sign_in to the binaray_selection_path. This will result in a HTTP GET request. In your users_controller you try to get a attribute from the params that simple does not exist. There is no params[:user], because the form was not sent yet.
You need to redirect the user to a page were the form is rendered.
I advise to read this guide: http://guides.rubyonrails.org/getting_started.html#getting-up-and-running
Your form is not submitting the values properly may be. So inspect your params in the binery select action.
record#update_attributes doesn't take a single value, it accepts hash. So the proper code should be something like:
rails version < 4
if #user.update_attributes(params[:user])
in rails 4.*
if #user.update_attributes(user_params)
in controller make sure you have permitted the user parameters.
Hello I'm very new to ruby on rails. Here i have form
<%= form_tag do %>
<%= text_field_tag :fullname, params[:fullname], placeholder: 'fullname' %>
.
.
.
<%= submit_tag "save" %>
<% end %>
Those form is to update model data. In my controller I have
def updateUser
user = Users.find(session[:user_id])
user.fullname = params[:fullname]
user.save
render 'profile'
end
It's not working (data doesn't updated), but when I tried
def updateUser
user = Users.find(session[:user_id])
user.fullname = 'david'
user.save
render 'profile'
end
It's working (the data updated). I don't know where did I go wrong, please kindly help me. Sorry for asking such easy question, I'm a newbie to Ruby (and so does Rails), I searched but didn't get a suitable answer for this case. Thank you
I'm very new to ruby on rails
Welcome - let me give you some ideas!
--
Form
Firstly, your form_tag is not created properly. You need to put a route in this (so it knows where to submit the data):
<%= form_tag your_path_here do %>
This is for the form_tag helper, however, as you're editing an object, you'll probably be better using the form_for helper - which takes an actual object (value):
<%= form_for #user do |f| %>
<%= f.text_field :full_name %>
<%= f.submit "Submit" %>
<% end %>
This type of form has to be used with the resourceful structure of Rails, which is my second point...
--
Resources
Rails is built around the idea of a resourceful infrastructure (where every data object is a resource). If you're updating / editing an object, the typical explanation is that you'll be editing a resource, and consequently will want to employ rails' resourceful structure to handle it:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:edit, :update, :show]
def index
#users = User.all
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
#user.save
end
def edit
end
def update
#user.update(user_params)
end
private
def user_params
params.require(:user).permit(:fullname, :etc)
end
def set_user
#user = User.find params[:id]
end
end
This will allow you to define the resourceful routes for this:
#config/routes.rb
resources :users
Using this setup with form_for will work for you
Didn't notice in the beginning. Your form is incorrect. You did not specify a URL for action, and you put your submit tag within a link so basically your link is getting called not your form submitted.
<%= form_tag '/userEdit' do %>
<%= text_field_tag :fullname, params[:fullname], placeholder: 'fullname' %>
.
.
.
<%= submit_tag "save" %>
<% end %>
Make sure that you have specified a route for userEdit post method.
I'm working to build a Rails 3 + devise, user registration page. This will be an additional page that does not replace the existing devise registration page. This page will include user info and billing info.
I'm trying to get the form to submit and if the form fields do not save, have the reloaded page include the user's previously inputted data. Here's a snippet:
<%= form_for(User.new, :url => '/pricing/sign_up') do |f| %>
<%= f.label :email %>
<%= f.email_field :email %>
<% end %>
When the form submits with invalid data. When the view re-renders, the existing email entered is not persisted. How can I make the existing user's input persist to help the user quickly correct mistakes and submit a valid form?
The key is to have the form_for use the right object. So, instead of
<%= form_for(User.new, :url => '/pricing/sign_up') do |f| %>
you should be using an instance variable to contain the object, like this
<%= form_for(#user, :url => '/pricing/sign_up') do |f| %>
The controller actions would look like this:
# Note: this may need to be an `edit` method instead?
def new
#user = User.new
end
# Note: this may need to be an `update` method instead?
def create
#user = User.new(params[:user])
if #user.save
# Do something... Usually a redirect with success message.
else
render :new
end
end
What this create method is doing is it's filling the #user object with params from the form. And then the call to #user.save will, behind the scenes, call #user.valid? and, if no errors are returned, then the record is saved to the database. But this part is key. If #user.valid? does result in errors, then the errors collection on #user will be populated. Then, after the render :new completes, and re-renders your user form, the form will be able to spit out errors messages by accessing the #user.errors collection. Otherwise, the way you had it before, you always had a User.new object in the form which would never have had any errors because it was never used to attempt record validation before.
How to display the errors in your form is a matter of preference and a little beyond the scope of this question. Here's a guide: http://guides.rubyonrails.org/active_record_validations.html#displaying-validation-errors-in-views
I think it's because of your form_for declaration where you're creating new instance of User on every call.
If you move the User.new to your controller and render the new action upon failure in create action then you should see the user entered values in the form fields.
Something like the following should work:
# app/controllers/users_controller.rb
def new
#user = User.new
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
...
else
format.html { render :new }
end
end
end
Then in your view:
<%= form_for(#user, :url => '/pricing/sign_up') do |f| %>
<%= f.label :email %>
<%= f.email_field :email %>
<% end %>
The values of the form fields are driven by the model you pass to form_for, so in your case they will always be empty because you are passing a brand new user object.
You should be using an instance variable which is set in the controller; in the new action this will be a new User model but in the create action it will be a model which has attributes set via the form:
# app/controllers/users_controller.rb
def new
#user = User.new
end
def create
#user = user.create(user_params)
if #user.save
redirect_to user_path(#user)
else
render :new
end
end
Then in the form:
<%= form_for(#user, :url => '/pricing/sign_up') do |f| %>
<%= f.label :email %>
<%= f.email_field :email %>
<% end %>