I am getting an error in Rails 3.2 with devise - my view is saying undefined method on line 1 below (user). This view is an edit profile page for logged in users.
So far I've tried changing this to current_user and defining that in my controller which I've provided below, but that did not work.
My only other suspicion is that form_for is not appropriate to use on this page?
<%= 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| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :username %><br>
<%= f.text_field :username %>
</div>
<div class="field">
<%= f.label :firstname %><br>
<%= f.text_field :firstname %>
</div>
<div class="field">
<%= f.label :lastname %><br>
<%= f.text_field :lastname %>
My controller... (as I said I tried current_user)
class UsersController < ApplicationController
def current_user
#current_user ||= User.find(session[:user_id])
end
def find
#user = User.new
end
def show
#user = User.find(params[:id])
end
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
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(:username, :firstname, :dateofbirth, :lastname, :gender, :location, :email, :password)
end
end
Devise comes with a current_user helper method. You probably don't want to override that, so I'd recommend removing that method from your controller. In one of my apps I allow users to edit their info and this is my edit method:
def edit
#user = current_user
end
Related
I'm currently building this website in college for fun. My hope is that it will help the education system. Anyways, I'm still trying to figure out rails. I just set up the devise gem with no problem. However, when I click post a new status it gives me this error:
NoMethodError in Statuses#new
Showing /Users/wyatt/Network/netbook/app/views/statuses/_form.html.erb where line #16 raised:
undefined method `user_name' for #<Status:0x00000101ec36d0>
Extracted source (around line #16):
13:
14: <div class="field">
15: <%= f.label :user_name %><br />
16: <%= f.text_field :user_name %>
17: </div>
18: <div class="field">
19: <%= f.label :content %><br />
So here's what my form looks like:
<%= form_for(#status) 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.label :user_name %><br />
<%= f.text_field :user_name %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Here's my controller
class StatusesController < ApplicationController
# GET /statuses
# GET /statuses.json
def index
#statuses = Status.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #statuses }
end
end
# GET /statuses/1
# GET /statuses/1.json
def show
#status = Status.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #status }
end
end
# GET /statuses/new
# GET /statuses/new.json
def new
#status = Status.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #status }
end
end
# GET /statuses/1/edit
def edit
#status = Status.find(params[:id])
end
# POST /statuses
# POST /statuses.json
def create
#status = Status.new(params[:status])
respond_to do |format|
if #status.save
format.html { redirect_to #status, notice: 'Status was successfully created.' }
format.json { render json: #status, status: :created, location: #status }
else
format.html { render action: "new" }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# PUT /statuses/1
# PUT /statuses/1.json
def update
#status = Status.find(params[:id])
respond_to do |format|
if #status.update_attributes(params[:status])
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 = Status.find(params[:id])
#status.destroy
respond_to do |format|
format.html { redirect_to statuses_url }
format.json { head :no_content }
end
end
end
From looking at it, it seems you're wanting to append a user_name to a status
Error
Your error basically means you don't have a user_name column in your statuses data table. The basic fix will be to create a migration to add a user_name column to your statuses db:
$ rails generate migration AddUserNameToStatuses
#db/migrations/AddUserNameToStatuses.rb
class AddUserNameToStatuses < ActiveRecord::Migration
def change
add_column :statuses, :user_name, :string
end
end
$ rake db:migrate
Fix
I would actually ditch that, and do this:
#app/models/status.rb
Class Status < ActiveRecord::Base
belongs_to :user #-> you need user_id column in statuses db
delegate :name, to: :user, prefix: true
end
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :statuses
end
This will allow you to remove the references to user_name from your form - as any #status will be associated with a user
You'd then be able to use the .delegate() method to call user_name in statuses
I'm learning Rails, and I would like to use simple_form.
I'm creating a simple app (my first one), and I want to create a signup form.
I used rails g scaffold User username:string password:string to create my model and controller.
I'm using Foundation gem too, if that's matter, and I install simple_form with the right command for Foundation.
I've been looking for answers for two hours, I tried many things, I have no idea of what's wrong with my code.
## app/views/home/index.html.erb ##
<%= simple_form_for #User do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<% end %>
## app/models/user.rb ##
class User < ActiveRecord::Base
end
## app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
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(:username, :password)
end
end
I'm obviously doing something wrong, and I'm pretty sure I will feel like an idiot, but it's my first app :/
Thanks you.
EDIT: I forgot to say, I tried (desperately) every vars (#user, #users, #User, #Users), any of them doesn't works :/
Get rid of the form from the index.html.erb view (and no, don't put it in show.html.erb either!).
Place this form in the new.html.erb view:
<%= simple_form_for #user do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<%= f.submit %>
<% end %>
Note that the form should reference #user not #User.
Yep ... in the view you are using the #User instance variable (with uppercase U) but in the controller you assign the model to the #user instance variable (with lowecase u) :)
Put #user in lowcase (not #user)
<%= simple_form_for #user do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<% end %>
And save it as new.html.erb view not index.html.erb!
I have a class called "questions", which is similar to an article, and each of them can have comments. Now the problem is, that I want to show multiple questions on the index page and all displaying the comments of the specific question as well as a small little form to leave a comment, which should be added to its question. Basically I have added the form and done everything, apart from figuring out how to get the question id and pass it to the comment.
I have made a little screenshot as well: http://prntscr.com/2pjk0i
questions_controller.rb
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
# GET /questions
# GET /questions.json
def index
#current_user ||= User.find_by_id(session[:user_id])
#questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
end
# GET /questions/new
def new
#question = Question.new
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
#current_user ||= User.find_by_id(session[:user_id])
#question.update(:user_id => #current_user.id)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render action: 'show', status: :created, location: #question }
else
format.html { render action: 'new' }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :body)
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
# GET /comments
# GET /comments.json
def index
#current_user ||= User.find_by_id(session[:user_id])
#comments = Comment.all
end
# GET /comments/1
# GET /comments/1.json
def show
end
# GET /comments/new
def new
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
#current_user ||= User.find_by_id(session[:user_id])
#comment.update(:user_id => #current_user.id, :question_id => ?) # What to add here to get the specific question id?
respond_to do |format|
if #comment.save
format.html { redirect_to '/', notice: 'comment was successfully created.' }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to '', notice: 'comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to '' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:title, :body)
end
end
index.html.erb
<h1>Listing questions</h1>
<%= link_to 'New Question', new_question_path %>
<hr>
<% #questions.each do |question| %>
<!-- Author -->
<%= question.user.name %> <br>
<!-- Date -->
<%= question.created_at %> <br>
<!-- Title -->
<%= question.title %> <br>
<!-- Body -->
<%= question.body %> <br>
<%= question.id %> <br>
<!-- Comment count -->
<%= question.comments.size %> Comment <br>
<!-- Comments -->
<% question.comments.each do |comment| %>
<!-- Comment Author -->
<%= comment.user.name %> <br>
<!-- Comment Date -->
<%= comment.created_at %> <br>
<!-- Comment Body -->
<%= comment.body %> <br>
<% end %>
<%= form_for(question.comments.new) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<hr>
<% end %>
Thank you in advance for your help! :)
The form_for will need to submit the question_id somehow - either by a route or through the form. I recommend a route.
If you don't interact with comments independently - if there is always a question, then change your routes to something like this:
resources :questions do
resources :comments
end
Then - in your form for, you will do this
<%= form_for [question, question.comments.new] do |f| %>
This will cause the form to submit (POST) to /question/:question_id/comments and you can handle it from there.
In the comments controller - you'll get the question from the params[:question_id] and return the result via an ajax response (respond to json).
This part is still tricky if you haven't done it before. If you need help with that part, you can probably find good examples or ask a separate question...
you can add hidden field inside your form
<%= f.hidden_field :question_id, value: question.id %>
or you can change your form
<%= form_for :comment, :url => comments_path(question_id:question.id) do |f| %>
<div class="field">
<%= f.label :body %><br>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
when u submit this form u will have url like /comments?question_id=id
I am new to rails.I have some confusion about about rails object life cycle.In rails we have the bellow code.
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
then in the form we have
<%= 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| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
my confusion is in the new action in controller i have #user = User.new
and again in the create #user = User.new(params[:user]).
then in form i have <%= form_for(#user) do |f| %> .
My question is here at the form the #user object actually means waht?
I mean does this #user is going to hit the new action or create action.
If it is going to hit the create action then how this is happening because the form is actually comes from the new action so i can't figure it out how its hitting to the create action .
i know its very simple question.But i dont know how its happening as i am new to rails.
Please help me to make me understand the object flow.
thanks in advance.
The "new" action makes a new object and shows a form for editing it. That form submits to the "create" action because the object has not been saved yet.
If you did
form_for #user
and #user was a previously-saved object, the form would submit to the update action instead.
form_for is a bit magical, like a lot of rails: it does two things:
sets the "action" attribute of the form to point at either "/users" (for create) and "/users/:id" (for update)
in the case of update (ie for objects that already have an id) it also adds a hidden field which triggers the update action: this hidden field will look like this: <input type="hidden" value="put" name="_method">.
Have a look at form_for in your rails api.
It's hitting create action because of the proper form URL. When you run rake routes command, you'll see that POST /users leads to users#create action - and that's the URL in the new form. URL is set (and form fields are generated) properly by Rails because you pass User instance to the form.
I guess the title is self explanatory...how do I make only authenticated users to create a user with devise?
when I try to add a new one (when authenticated), devise says that I'm alreade authenticated
any workaround for this?
thanks a lot
edit: as requested, my code
user form
<% if #user == current_user %>
<i class="icon-info-sign"> </i><i>Após alterar seus dados, você terá de fazer login novamente</i>
<% end %>
<%= form_for(#user, :html => { :class => "well form-horizontal"}) do |f| %>
<% if #user.errors.any? %>
<div class="alert alert-error">
<h2><%= pluralize(#user.errors.count, "erro") %>
<% if #user.errors.count == 1 %> impede
<% else %>
impedem
<% end %>
a continuação:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<label>Nome</label><%= f.text_field :nome %>
<label>E-mail</label><%= f.email_field :email %>
<% if #user == current_user or #user.created_at == nil%>
<label>Senha</label><%= f.password_field :password %>
<% end %>
<div>
<br />
<button class="btn" type="submit">
Salvar alterações
</button>
</div>
<% end %>
part of users controller
before_filter :authenticate_user!
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
application controller
class ApplicationController < ActionController::Base
protect_from_forgery
def after_sign_in_path_for(resource)
return request.env['omniauth.origin'] || stored_location_for(resource) || painel_path
end
end
part of routes
App::Application.routes.draw do
resources :acampantes
devise_for :users, :skip => [:registrations]
resources :profiles
resources :eventos do
resources :acampantes
end
# aqui tem um has_many, mas não precisa de nested routes
resources :noticias
resources :users#, :as => "usuarios"
The ideal way to do it would be to override registrations_controller.rb (as shown here) and skipping the before_filter check for the new and create action. I tried to do it myself, but unfortunately, I couldn't get it right.
Another way to do it, which worked for me, would be to create a separate User controller aside from the Registrations controller provided by Devise:
class UsersController < ApplicationController
before_filter :authenticate_user!
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "User saved"
redirect_to #user
else
render 'new'
end
end
end
# routes.rb
ApplicationName::Application.routes.draw do
devise_for :users
resources :users, :only => [:new, :create]
end
Then make a form for the new action:
# app/views/users/new.html.erb
<%= form_for(#user) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
The problem with this approach is that the routes provided by Devise for signing-up still exists. A solution for that would be to prevent Devise from generating routes involving registration:
# routes.rb
devise_for :users, :skip => [:registrations]
This means that you are going to ignore the Registrations module completely and make your own. I got this idea from the Bare-bone, stripped-down Devise tutorial. Take note that you should make the controller actions and views to replace the ones provided by the registrations module of Devise. This includes new, edit, create, update, and destroy.