Gone through a lot of answers but still couldn't find the solution.
I have been trying to get a successful response for a POST request to the following controller,
def create
#user = User.new(user_params)
if #user.save
render json: #user, status: :created, location: #user
else
render json: #user.errors, status: :unprocessable_entity
end
private
def user_params
params.require(:user).permit(:name, :email, :phone, :password)
end
end
Although I send all the parameters mentioned,in the request,I am still facing the error.
"status": 400,
"error": "Bad Request",
"exception": "#<ActionController::ParameterMissing: param is missing or the value is empty: user>"
I am using rails version 5.2.1
If you look at the logs, what does the data transferred in your post request look like?
When you get that type of error, often it's because you send the data like this:
{ first_name: 'John', last_name: 'Doe', ...}
When the server expects you to nest this into a user object (hence the require(:user) in your strong_params:
{ user: { first_name: 'John', ... } }
This is Worked for me.
I made just only one hash in params method instead of nested hash.
my user_params method was:-
def user_params
params.permit(:name, :email, :phone, :password)
end
OR You can you your method but your paramter passed in user hash like below.
{user: {name: "bittu", email: "abc#yopmail.com", phome: 123456, password: "123456" } }
Related
I am using the
MailForm Gem
to create a contact form for my app and everything seems to be working just fine so I decided to write some tests to make sure it stays that way.
class ContactsControllerTest < ActionDispatch::IntegrationTest
def setup
ActionMailer::Base.deliveries.clear
end
test "should send contact email" do
get contact_path
post contacts_path, params: { contact: {
name: "interested customer",
email: "interested#customer.com",
subject: "we are interested!",
message: "we are so interested!!!"
}}
assert_equal 1, ActionMailer::Base.deliveries.size
assert_redirected_to root_path
end
test "should not send invalid contact email" do
get contact_path
post contacts_path, params: { contact: {
name: "",
email: "",
subject: "",
message: ""
}}
assert_equal 0, ActionMailer::Base.deliveries.size
assert_template 'contacts/new'
end
test "should not send contact email with captcha filled" do
get contact_path
post contacts_path, params: { contact: {
name: "interested customer",
email: "interested#customer.com",
subject: "we are interested!",
message: "we are so interested!!!",
nickname: "not_blank"
}}
assert_equal 0, ActionMailer::Base.deliveries.size
assert_template 'contacts/new'
end
the first two tests pass while the third fails with the message
FAIL["test_should_not_send_contact_email_with_captcha_filled", ContactsControllerTest, 5.2574800989968935]
test_should_not_send_contact_email_with_captcha_filled#ContactsControllerTest (5.26s)
Expected: 0
Actual: 1
test/controllers/contacts_controller_test.rb:35:in `block in <class:ContactsControllerTest>'
My model looks like this.
class Contact < MailForm::Base
attribute :name, :validate => true
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+ ([\w]{2,})\z/i
attribute :subject
attribute :message
attribute :nickname, :captcha => true
def headers
{
:subject => "Contact: #{subject}" ,
:to => "myemail#mail.com",
:from => %("#{name}" <#{email}>)
}
end
end
My first thought was that the captcha validation is not stopping the mail from being sent. If someone could point out what I am missing I would appreciate it.
The mailform model returns valid, even if the nickname is given. But you can check if it is spam, which prohibits the mail from being sent.
I use this to check if the spam detection works(with rspec):
it 'should be marked spam if it contains :nickname' do
expect(FactoryGirl.build(:contact_with_nickname)).to be_spam
end
I am trying to insert some default users in my project using seed.rb file. I have executed the following line in the console:
rake db:seed
and no errors were thrown, but the records were not created either. When I paste the code in the rails console, again no errors are shown. I am guessing that I am doing something wrong in the seed.rb file.
This is how my models are related:
security_user.rb
has_one :security_users_detail, dependent: :destroy
has_many :security_users_manage_securities
has_many :security_users_roles, through: :security_users_manage_securities
security_users_detail.rb
belongs_to :security_user
security_users_role.rb
has_many :security_users_manage_securities
has_many :security_users, through: :security_users_manage_securities
And this is the code that I have in my seed.rb file:
users = {
Admin: {
Information: {
email: 'test#gmail.com',
password: 'test',
password_confirmation: 'test'
},
Details: {
address: 'Not defined.',
city: 'Not defined.',
country: 'Not defined.',
egn: '0000000000',
faculty_number: '',
first_name: 'Admin',
gender: 'male',
gsm: '0000000000',
last_name: 'Not defined.',
skype: 'Not defined.'
},
Roles: %w(Administrator)
}
}
users.each do |user, data|
security_user = SecurityUser.new(data[:Information])
data[:Roles].each { |role|
security_user.security_users_manage_securities.build(security_users_role: SecurityUsersRole.find_by_role(role))
}
SecurityUser.where(email: security_user.email).first_or_create!(security_user.attributes)
security_users_detail = SecurityUsersDetail.new(data[:Details])
security_users_detail.security_user_id = security_user.id
SecurityUsersDetail.where(security_user_id: security_users_detail.security_user_id).first_or_create
end
seed.rb is a rake task, so you can use puts to output messages to the console. For instance,
puts "User name: #{user.name}"
The issue was caused by the following line:
security_user = SecurityUser.new(data[:Information])
because even thought the hash passed in the new method holds only email and password fields, the result object was created with the rest of the model attributes but set to nil. For, example, I have id=>nil.
Then in I was doing the following
SecurityUser.where(email: security_user.email).first_or_create!(security_user.attributes)
in order to created the user only if exists. Anyway, since the id parameter is not in the attr_accessible clause in the model, I was not able to make mass assign.
To delete the nil values of the hash I've done the following:
SecurityUser.where(email: security_user.email)
.first_or_create!(security_user.attributes
.delete_if { |key, value| value.nil? })
I'm trying to mock a user models save method to return false, and simulate what the controller would do in case of validation failure.
My spec looks like:
require 'spec_helper'
describe UsersController do
describe 'POST create_email_user' do
it 'responds with errors json if saving the model fails' do
#params = {
:last_name => 'jones',
:email => 'asdfasdfasfd#'
}
User.stub(:new_email_user) .with(#params) .and_return(#mock_user)
#mock_user.stub(:save) .and_return(false)
post :create_email_user, :user => #params, :format => :json
response.body.should == #mock_user.errors.as_json
response.status.should == :unprocessable_entity
end
end
end
Controller action looks like:
class UsersController < ApplicationController
def create_email_user
#user = User.new_email_user(params[:user])
if #user.save
# code left out for demo purposes
else
render json: #user.errors, status: :unprocessable_entity
end
end
end
When running this spec, I get the error that basically says the expected call to new_email_user got the wrong arguments:
1) UsersController POST create_email_user responds with errors json if saving the model fails
Failure/Error: post :create_email_user, :user => #params, :format => :json
<User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, uid: string, provider: string, first_name: string, last_name: string, registration_id: integer, gender: string, authentication_token: string) (class)> received :new_email_user with unexpected arguments
expected: ({:last_name=>"jones", :email=>"asdfasdfasfd#"})
got: (["last_name", "jones"], ["email", "asdfasdfasfd#"])
Please stub a default value first if message might be received with other args as well.
It seems like rails converts the has to an array of key value pairs, while my code is just using the straight hash in the setup.
How can I simulate this converting to an array, or am I doing else wrong?
Drop the .with stub on user, since it isn't really relevant to the test and it is causing problems.
Without the .with the stub will return that value for any arguments.
So:
User.stub(:new_email_user).and_return(#mock_user)
I would then have a separate spec which ensures that:
User.should_receive(:new_email_user).with(#params)
And diagnose that problem in its own, narrow spec.
I've got a Template model, and a Doc model. They're nested resources, with the Templates being the parent, thus:
resources :templates do
get "/documents/lock/:id" => "docs#lock", :as => :lock_doc
get "/documents/unlock/:id" => "docs#unlock", :as => :unlock_doc
get "/documents/pdf/:id" => "docs#pdf", :as => :pdf_doc
resources :docs, :path => :documents
end
That part, I think, all works fine. When I try to submit the form for creating a doc the record exists but I get routing errors, thus:
ActionController::RoutingError (No route matches {:action=>"edit", :controller=>"docs", :template_id=>nil, :id=>#<Doc id: 2, user_id: "admin", cover: "1209hpnl", message: "The world economic outlook is improving, albeit slo...", created_at: "2013-01-07 03:54:05", updated_at: "2013-01-07 03:54:05", issue_code: "1209hpnl", title: "January 2013", locked: nil, retired: "active", template: nil>}):
app/controllers/docs_controller.rb:134:in `block (2 levels) in create'
app/controllers/docs_controller.rb:132:in `create'
The lines correspond to the create method:
def create
#doc = Doc.new(params[:doc])
respond_to do |format|
if #doc.save
format.html { redirect_to share_url(#doc), notice: "Saved. You may from here #{view_context.link_to('edit', edit_template_doc_url(#doc))} it further, #{view_context.link_to('finalise', template_lock_doc_url(#doc))} it, or return #{view_context.link_to('home', root_url)}.".html_safe }
format.json { render json: #doc, status: :created, location: #doc }
else
format.html { render action: "new" }
format.json { render json: #doc.errors, status: :unprocessable_entity }
end
end
end
I think the problem lies somewhere in here, but I can't for the life of me figure it out.
Cheers for any help!
EDIT: with rake routes
template_lock_doc GET /templates/:template_id/documents/lock/:id(.:format) docs#lock
template_unlock_doc GET /templates/:template_id/documents/unlock/:id(.:format) docs#unlock
template_pdf_doc GET /templates/:template_id/documents/pdf/:id(.:format) docs#pdf
template_docs GET /templates/:template_id/documents(.:format) docs#index
POST /templates/:template_id/documents(.:format) docs#create
new_template_doc GET /templates/:template_id/documents/new(.:format) docs#new
edit_template_doc GET /templates/:template_id/documents/:id/edit(.:format) docs#edit
template_doc GET /templates/:template_id/documents/:id(.:format) docs#show
PUT /templates/:template_id/documents/:id(.:format) docs#update
DELETE /templates/:template_id/documents/:id(.:format) docs#destroy
templates GET /templates(.:format) templates#index
POST /templates(.:format) templates#create
new_template GET /templates/new(.:format) templates#new
edit_template GET /templates/:id/edit(.:format) templates#edit
template GET /templates/:id(.:format) templates#show
PUT /templates/:id(.:format) templates#update
DELETE /templates/:id(.:format) templates#destroy
The problem is in your call to edit_template_doc_url(#doc) inside the notice string. You need to supply the template as well, like this:
edit_template_doc_url(params[:template_id], #doc)
I have the following rspec test:
def valid_attributes
{ "product_id" => "1" }
end
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, {:line_item => valid_attributes}, valid_session #my valid_session is blank
}.to change(LineItem, :count).by(1)
end
Which fails with this error:
1) LineItemsController POST create with valid params redirects to the created line_item
Failure/Error: post :create, {:line_item => valid_attributes}, valid_session
ActiveRecord::RecordNotFound:
Couldn't find Product without an ID
# ./app/controllers/line_items_controller.rb:44:in `create'
# ./spec/controllers/line_items_controller_spec.rb:87:in `block (4 levels) in <top (required)>'
This is my controller's create action:
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.line_items.build(:product => product)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render json: #line_item.cart, status: :created, location: #line_item }
else
format.html { render action: "new" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
As you can see, my action expects a product_id from the request's params object. How should I work this product_id into my rspec test?
I've tried placing this before statement:
before(:each) do
ApplicationController.any_instance.stub(:product).and_return(#product = mock('product'))
end
. . . but it changes nothing. I am missing some rspec concept here somewhere.
Try like this:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => 1
}.to change(LineItem, :count).by(1)
end
Hope it helps.
I ended up resolving my issue by using a fixture instead of attempting to mock the solution as suggested in another answer.
The reason for this is that the controller does the query to get information from the database: product = Product.find(params[:product_id]) and I found a fixture-based solution was quicker to resolve my problem than one using a mock and I could not figure out how to stub the query quickly (the fixtures also help with another test on the controller so it eventually helped anyway.
For reference:
I referenced my fixture with this line toward the top of the test: fixtures :products
I changed my test to:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => products(:one).id
}.to change(LineItem, :count).by(1)
end
And here is my fixture file, products.yml:
one:
name: FirstProduct
price: 1.23
two:
name: SecondProduct
price: 4.56