Rails - ArgumentError in UsersController#create - too few arguments - ruby-on-rails

This is probably really basic but I can't seem to figure it out.
Essentially, when I try to create a new user using a form, and the user details are already present and not unique, I receive he following error:
ArgumentError in UsersController#create
too few arguments
Application Trace | Framework Trace | Full Trace
app/controllers/users_controller.rb:61:in `format'
app/controllers/users_controller.rb:61:in `create'
Here's my create action in my user_controller.rb:
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = 'User successfully created' and redirect_to :action=>"index"
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
And here's my user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :username, :password, :password_confirmation, :remember_me
validates :email, :username, :presence => true, :uniqueness => true
end
Here's also my form:
<%= simple_form_for(#user) do |f| %>
<div class="field">
<%= f.input :username %>
</div>
<div class="field">
<%= f.input :email %>
</div>
<div class="field">
<%= f.input :password %>
</div>
<div class="field">
<%= f.input :password_confirmation %>
</div>
<div class="actions">
<%= f.button :submit %>
</div>
<% end %>

What's format in this case?
There's no respond_to block, put it back in! You're referencing some other format.

The exact layout of the code has changed a bit through different rails version (please post what version you are using - check the Gemfile).
This example is for rails 3+ (it was generated using 3.2.5 but should apply to all 3+ or at least 3.1+ versions)
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'Blob 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
p.s. Good choice with simple_form, it makes life MUCH easier!

Related

Rails 'required: true' does not work fully

I have a simple_form with a grouped collection select and two input fields. I have a required: true on both fields, but it still allows empty input through. The little 'required' asterisk appears next to the field name, but that's it. Is there any way I can prevent empty input from going through the form?
new.rb
<h1>New Article</h1>
<%= render 'form', article: #article %>
<%= link_to 'Back', articles_path(category_id: params[:category_id]) %>
_form.rb
<%= simple_form_for(article, html: {class: 'form-vertical'}) do |f| %>
<% if article.errors.any? %>
<div id="error_explanation">
<h4><%= pluralize(article.errors.count, "error") %> prohibited this article from being saved:</h4>
<ul>
<% article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%# field being selected, parent collection, subcollection, displayed, key, value %>
<%= f.grouped_collection_select :subcategory_id, Category.all,:subcategories,:name, :id,:name, {required: true} %>
<%= f.input :title, required: true %>
<%= f.input :content, input_html: { rows: 20 }, required: true%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
articles_controller.rb
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
# GET /articles
# GET /articles.json
def index
if params[:category_id].blank? && params[:subcategory_id].blank?
#articles = Article.all.order("created_at DESC")
elsif params[:subcategory_id].blank?
#articles = Article.where(category_id: params[:category_id])
else
#articles = Article.where(subcategory_id: params[:subcategory_id]).order("created_at DESC")
end
end
# GET /articles/1
# GET /articles/1.json
def show
end
# GET /articles/new
def new
#article = Article.new
end
# GET /articles/1/edit
def edit
end
# POST /articles
# POST /articles.json
def create
#parameters = article_params
#parameters[:category_id] = Subcategory.find(#parameters[:subcategory_id]).category_id
#article = Article.new(#parameters)
respond_to do |format|
if #article.save
format.html { redirect_to #article, notice: 'Article was successfully created.' }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
respond_to do |format|
if #article.update(article_params)
format.html { redirect_to #article, notice: 'Article was successfully updated.' }
format.json { render :show, status: :ok, location: #article }
else
format.html { render :edit }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
#article.destroy
respond_to do |format|
format.html { redirect_to root_path, notice: 'Article was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params.require(:article).permit(:title,:content,:subcategory_id)
end
end
As per simple documentation of rails. Your model should look like this(suppose i wanted to validate presence of first_name last_name and compnay_name):
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates :company_name, presence: true
validates :first_name, presence: true
validates :last_name, presence: true
end
Now after this you are ready to go, presence: true will validate data before saving it to the database. A good practice is to add a validation to the front end too. which is add require: true to your form_for helper.
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name, autofocus: true, required: true ,autocomplete: "email", class: "border p-3 w-100 my-2" %>
</div>
You need to use validations, that logic is done inside the model.
Make sure you read and undertand the ActiveRecord Validations Guide because it will save you a lot of time.
Example taken from the guide:
class Person < ApplicationRecord
validates :name, presence: true
end
Person.create(name: "John Doe").valid? # => true
Person.create(name: nil).valid? # => false
Basically when the object is saved, it runs the validations and if it's not valid it will fill the errors variable with the messages.
Simple form documentation states...
By default all inputs are required. When the form object has presence
validations attached to its fields, Simple Form tells required and
optional fields apart. For performance reasons, this detection is
skipped on validations that make use of conditional options, such as
:if and :unless.
Which means that all you need to do is add into your model/article.rb file
class Article < ActiveRecord::Base
validates :title, presence: true
validates :content, presence: true

Comment functionality in Rails. undefined method `first_name' for nil:NilClass

One thing I could never do properly is implement a comment feature. I'm not leaving my computer until I learn to do it.
The error is thrown on this line:
<strong><%= comment.user.first_name %></strong>
Apparently user is nil; but why? And what do I have to do to get this to work?
A comment should belong to a guide and a user. Users and guides both have many comments.
I started with
rails g scaffold comment body:text guide:references user:references
and then migrated the database. I completed the model associations as well.
Here is my guides controller show action:
def show
#guide = Guide.find(params[:id])
#comment = #guide.comments.build
end
Here is the part of the Guide show view that deals with comments:
<h3>Comments</h3>
<% #guide.comments.each do |comment| %>
<div>
<strong><%= comment.user.first_name %></strong>
<br />
<p><%= comment.body %></p>
</div>
<% end %>
<%= render 'comments/form' %>
Here is the comment form partial:
<%= simple_form_for(#comment) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :body %>
<%= f.association :user %>
<%= f.association :guide %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, #:recoverable,
:rememberable, :trackable, :validatable
validates :first_name, presence: true
validates :email, presence: true
validates :email, uniqueness: true
validates :runescape_username, presence: true
has_many :guides
has_many :comments
acts_as_voter
def user_score
self.guides.inject(0) { |sum, guide| sum += guide.score }
end
end
Comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :guide
end
Comments controller create action:
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, 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
Replace the line
#comment = Comment.new(comment_params)
with
#comment = current_user.comments.build(comment_params)
in your Comments#create action.
You get this error because you don't assign current_user to created Comment. That's why comment.user returns nil.
As stated by AndreDurao, you can also validate user_id presence in Comment model, like this:
class Comment
validates_presence_of :user
# ...
end
for getting rid of that error try this <%= comment.user.try(:first_name) %>

Rails 4, Devise associate users to post

I have Devise setup and can create posts, but I would like to add the username of the creator of the post.
Am I missing something?
posts controller:
def create
#post = current_member.posts.new(params[:post])
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
post model:
class Post < ActiveRecord::Base
belongs_to :member
end
member model: (I'm using member as user)
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts
end
In show.html I don't know what to put on the buttom to display the username. I get errors or it will just display the current user email on all post until i log out, then nil error of course.
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Author:</strong>
<%= #post.author %>
</p>
<p>
<strong>Main:</strong>
<%= #post.main %>
</p>
<%= current_member.email %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Back', posts_path %>
I presume you don't want the logged-in member/user's e-mail with the post but instead the author's e-mail. Try: #post.member.email

Devise sign in not completing

I have a normal Devise install with my Users model. The sign up and sign out work fine but the sign in form simply redirects back to the sign in page.
I've kept almost everything default:
session/new.html.erb
<h2>Sign in</h2>
<%= form_for(resource, :as => resource_name, :url => user_session_path) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div><br/>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div><br/>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<div><%= f.submit "Sign in" %></div>
<% end %>
users_controller.rb
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])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
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
routes
devise_for :users, path_names: {sign_in: "login", sign_out: "logout"}
resources :users
Here are the logs created after attempting to sign in.
Started POST "/users/login" for 127.0.0.1 at 2013-02-13 19:18:34 -0600
Processing by Devise::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"oPVQIraxxQ3m8I4hbqy0r/BLIUaESkNDLFhvtoRIf2Q=", "user"=>{"email"=>"MYEMAIL#gmail.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
Completed 401 Unauthorized in 1ms
Processing by Devise::SessionsController#new as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"oPVQIraxxQ3m8I4hbqy0r/BLIUaESkNDLFhvtoRIf2Q=", "user"=>{"email"=>"MYEMAIL#gmail.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
Rendered devise/_links.erb (0.5ms)
Rendered devise/sessions/new.html.erb within layouts/application (5.5ms)
Completed 200 OK in 108ms (Views: 29.8ms | ActiveRecord: 0.0ms | Solr: 0.0ms)
I tried adding changing the form_for to the following:
<%= form_for(resource, :as => resource_name, :url => user_session_path(resource_name)) do |f| %>
but that sends me to http://localhost:3000/users/login.user which gives me this in the development logs:
Started POST "/users/login.user" for 127.0.0.1 at 2013-02-13 19:21:36 -0600
Processing by Devise::SessionsController#create as
Parameters: {"utf8"=>"✓", "authenticity_token"=>"oPVQIraxxQ3m8I4hbqy0r/BLIUaESkNDLFhvtoRIf2Q=", "user"=>{"email"=>"demeuseja#gmail.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
Completed 401 Unauthorized in 1ms
I'm sure it's a mistype or something that I'm overlooking since everything works besides the sign in, but I've been tinkering with it for hours and have no idea what the problem is. Any point in the right direction would be much appreciated!
Thanks!
EDIT
Here's my Users model as well:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
attr_accessible :bio, :employer, :looking, :name, :password, :statement, :user_id, :username
validates :name, :presence => true, :length => { :minimum => 3 }
has_many :venues
scope :employer, where(employer:true)
scope :looking, where(looking:true)
scope :recent, order("created_at_desc").limit(3)
end
So in order to temporarily fix this, I changed the the form in sessions/new.html.erb from the default:
<h2>Sign in</h2>
<%= form_for(resource, :as => resource_name, :url => user_session_path) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div><br/>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div><br/>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<div><%= f.submit "Sign in" %></div>
<% end %>
to the following:
<%= form_tag new_user_session_path do %>
<%= text_field_tag 'user[email]' %>
<%= password_field_tag 'user[password]' %>
<%= submit_tag 'Login' %>
<% end %>
Now the sign in works fine, as well as the sign up and sign out. I'm sure I'll have to go back and fix the real problem but at least now for testing purposes it works. If someone posts an actual fix instead of a workaround like this I'll accept their answer instead.
Thanks for your other answers!
Maybe it's me, but I can't see what you've changed in the form_for from your first example, but the second request path is incorrect.
For your first example, it is correctly using the Devise::SessionController create action to sign the user in but it is returning a 401 unauthorized. The controller you provided is the UserController, which handles the create and update actions for creating a new user. It is not relevant here.
Try taking out the resource_name on the url so it looks like:
<%= form_for :resource, as: :resource_name, url: user_session_path do |f| %>
It is a 401 unauthorized error being returned so you might want to try resetting the user password to see if that solves it first.
EDIT:
Based on the answer you provided below, it gave me another idea. The devise examples might be a bit dated, especially if you're doing anything slightly off with the sign-in form (although, it doesn't look like it). You could throw these in your application_helper which will ensure that the resource definitions are set. You can see documentation about it here:
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
Where User.new references your User model definition. Another idea is to strip out the resource stuff altogether, and just use your actual model names instead.
I haven't used a recent version of devise, but at a wild guess I'd say that:
path_names: {sign_in: "login", sign_out: "logout"}
means you should be using login_path instead of user_session_path
Again a wild guess you may have already tried... but, in your user controller do you have a "skip before filter authenticate" or similar?
If so - the sign-in actions generally need to skip that before-filter, or it'll fail to get to the action itself because "you haven't signed in yet" while you're still attempting to sign in.

RoR : Nested forms with devise

I am new to RoR and I thought I could ask you some help. I didn't find the specific answer I am looking for.
I have a problem with a modelisation I want to make using Devise. Devise sets up a Member model, and I want to have a SuperMember model which have more attributes than Member, and some different views.
I want to set up a nested form to create a SuperMember, while automatically creating the Member account in the background.
Member.rb (generated by devise)
class Member < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
end
SuperMember.rb
class Supermember < ActiveRecord::Base
attr_accessible :first_name, :last_name
belongs_to :member, :dependent => :destroy
accepts_nested_attributes_for :member
end
Supermembers.controllers.rb
def new
#supermember = Supermember.new
#supermember.member = Supermember.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #supermember }
end
end
def create
#supermember = Supermember.new(params[:supermember])
respond_to do |format|
if #supermember.save
format.html { redirect_to #supermember, notice: 'Supermember was successfully created.' }
format.json { render json: #supermember, status: :created, location: #supermember }
else
format.html { render action: "new" }
format.json { render json: #supermember.errors, status: :unprocessable_entity }
end
end
I tried to create a nested form in order to generate both the member and the supermember :
<%= simple_form_for(#supermember) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :first_name %>
<%= f.input :last_name %>
</div>
<% # Devise member %>
<%= f.fields_for :member do |m| %>
<div class="form-inputs">
<%= m.input :email, :required => true, :autofocus => true %>
<%= m.input :password, :required => true %>
<%= m.input :password_confirmation, :required => true %>
</div>
<% end %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
The problem is that when I submit this form, I get the following error message :
Can't mass-assign protected attributes: member_attributes
Application Trace | Framework Trace | Full Trace
app/controllers/supermembers.rb:44:in `new'
app/controllers/supermembers.rb:44:in `create'
I really don't understand how to fix it. Could you help me on this one?
Thank you very much!
You need to allow Supermember to accept mass assignment of the member attributes
class Supermember < ActiveRecord::Base
attr_accessible :first_name, :last_name, :member_attributes
...
end
If what you're trying to do is add attributes to member, then it is perfectly OK to do so. There's no need to create a supermember for that purpose only (of course, if you have some other agenda then go ahead...).
Device doesn't care if you add attributes to the model, even if it was generated by it.

Resources