I am attempting to use stub_chain to mock a series of calls in a controller action. However it is complaining about a method not found error. After a bunch of searching, I didn't really find any info relating to this specific error, so I figure I am missing something fairly obvious. Any ideas?
Thanks.
Here is the error:
Admin::AccountsController GET #index with accounts
Failure/Error: before(:each) { Account.stub_chain(:scoped, :page, :order).returns([account]) }
NoMethodError:
undefined method `stub_chain' for #<Class:0x007f96c6448158>
# ./spec/controllers/admin/accounts_controller_spec.rb:11:in `block (4 levels) in <top (required)>'
Source for the spec:
#spec/controllers/admin/accounts_controller.rb
describe 'GET #index' do
context 'with accounts' do
let(:account) { FactoryGirl.build_stubbed(:account) }
before(:each) { Account.stub_chain(:scoped, :page, :order).returns([account]) }
subject { get :index }
it { should render_template(:index) }
it { should assign_to(:accounts) }
it { should respond_with(:success) }
it { should_not set_the_flash }
end
end
Related
This is my first rails application. My task is to display, delete and update the records using .ajax(). I have displayed and deleted the records but i cant update the records i couldn't figure out what is going wrong. My controller code is
def update
#aj = Aj.find params[:id]
respond_to do |format|
if #aj.update(aj_params)
format.html { redirect_to #aj, notice: 'Aj was successfully updated.' }
format.json { render :show, status: :ok }
else
format.html { render :edit }
format.json { render json: #aj.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_aj
#aj = Aj.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def aj_params
params.require(:aj).permit(:name, :title, :content)
end
end
and my route file is
match '/ajs/' => 'ajs#update', :via => :patch
match '/ajs/:id/edit' => 'ajs#edit', :via => :get
and could able to edit my form after changing the data when i click on update button it given the error
Couldn't find Aj without an ID
# Use callbacks to share common setup or constraints between actions.
def set_aj
#aj = Aj.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
edited:
I have javascript code in html itself
$(document).on("click", ".edit", function(){
var id = $(this).data('id');
alert("edit"+id)
$.ajax({
url: "ajs/"+id+"/edit",
type: "get",
data: id,
//dataType: "html",
success: function(data) {
$("#mybox").html(data);
$(document).on("click", "#subid", function(){
alert(id);
$.ajax({
url: "ajs/"+id,
type: "patch",
success: function(data) {
alert("success");
},
error: function(){
alert("error")
}
}); // show ajax() closed
});//show click() closed
},
error: function(){
alert("error")
}
}); // show ajax() closed
});//show click() closed
I have added a id for the update button and id name is "subid " when i click on that button i am passing my id am getting id of the row. when i used ajax for passing that id now i am getting another error:
No route matches [PATCH] "/ajs"
Rails.root: /home/liplw015/Documents/rails/ajaxjs
In my console:
Started PATCH "/ajs/134" for 127.0.0.1 at 2014-07-14 09:38:09 +0530
Processing by AjsController#update as */*
Parameters: {"id"=>"134"}
Aj Load (0.4ms) SELECT "ajs".* FROM "ajs" WHERE "ajs"."id" = ? LIMIT 1 [["id", 134]]
Completed 400 Bad Request in 4ms
ActionController::ParameterMissing (param is missing or the value is empty: aj):
app/controllers/ajs_controller.rb:98:in `aj_params'
app/controllers/ajs_controller.rb:69:in `block in update'
app/controllers/ajs_controller.rb:68:in `update'
Rendered /home/liplw015/.rvm/gems/ruby-2.1.2/gems/actionpack- 4.1.2/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.9ms)
Rendered /home/liplw015/.rvm/gems/ruby-2.1.2/gems/actionpack-4.1.2/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb (1.3ms)
Rendered /home/liplw015/.rvm/gems/ruby-2.1.2/gems/actionpack-4.1.2/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb (0.9ms)
Rendered /home/liplw015/.rvm/gems/ruby-2.1.2/gems/actionpack-4.1.2/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb (22.5ms)
Started PATCH "/ajs" for 127.0.0.1 at 2014-07-14 09:38:10 +0530
ActionController::RoutingError (No route matches [PATCH] "/ajs"):
actionpack (4.1.2) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
your route is wrong, include id in route
match '/ajs/:id' => 'ajs#update', :via => :patch
i try to use TDD Rspec for model validation in rails 3.
my user_spec.rb file look like
require 'spec_helper'
describe User do
before { #user = User.new(name: "eric", country: "hawaii", email: "nice#nice.ch", password: "nicenice") }
subject { #user }
it { should respond_to(:name) }
it { should respond_to(:email) }
it { should be_valid }
end
after running rspec spec/models/user_spec.rb, i get an error message
No DRb server is running. Running in local process instead ...
..F
Failures:
1) User
Failure/Error: it { should be_valid }
TypeError:
type mismatch: String given
# ./spec/models/user_spec.rb:37:in `block (2 levels) in <top (required)>'
Finished in 0.09495 seconds
3 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:37 # User
Randomized with seed 42015
should be_valid expected a string?
I have a post method that accepts JSON:
post '/channel/create' do
content_type :json
#data = JSON.parse(env['rack.input'].gets)
if #data.nil? or !#data.has_key?('api_key')
status 400
body({ :error => "JSON corrupt" }.to_json)
else
status 200
body({ :error => "Channel created" }.to_json)
end
As a newbie to rspec I am bewildered trying to figure out how to write a test against that POST with an acceptable JSON payload. The closest I got to is this which is woefully inaccurate but I don't seem to be asking the Google god the right questions to help me out here.
it "accepts create channel" do
h = {'Content-Type' => 'application/json'}
body = { :key => "abcdef" }.to_json
post '/channel/create', body, h
last_response.should be_ok
end
Any best practice guidance for testing APIs in Sinatra will be most appreciated also.
The code you've used is fine, although I would structure it slightly differently as I don't like to use it blocks the way you normally see them, I think it encourages testing of more than one aspect of a system at a time:
let(:body) { { :key => "abcdef" }.to_json }
before do
post '/channel/create', body, {'CONTENT_TYPE' => 'application/json'}
end
subject { last_response }
it { should be_ok }
I've used let because it's better than an instance variable in a before block (kudos to you for not doing that). The post is in a before block because it's not really part of the spec, but a side effect that occurs prior to what you're speccing. The subject is the response and that makes the it a simple call.
Because checking the response is ok is needed so often I put it in a shared example:
shared_examples_for "Any route" do
subject { last_response }
it { should be_ok }
end
and then call it as such:
describe "Creating a new channel" do
let(:body) { { :key => "abcdef" }.to_json }
before do
post '/channel/create', body, {'CONTENT_TYPE' => 'application/json'}
end
it_should_behave_like "Any route"
# now spec some other, more complicated stuff…
subject { JSON.parse(last_response.body) }
it { should == "" }
and because the content type changes so often, I put that in a helper:
module Helpers
def env( *methods )
methods.each_with_object({}) do |meth, obj|
obj.merge! __send__(meth)
end
end
def accepts_html
{"HTTP_ACCEPT" => "text/html" }
end
def accepts_json
{"HTTP_ACCEPT" => "application/json" }
end
def via_xhr
{"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
end
It's easy to add this in where it's needed by including it via the RSpec config:
RSpec.configure do |config|
config.include Helpers, :type => :request
then:
describe "Creating a new channel", :type => :request do
let(:body) { { :key => "abcdef" }.to_json }
before do
post '/channel/create', body, env(:accepts_json)
end
Having said all that, personally, I wouldn't post using JSON. HTTP POST is simple to handle, and every form and javascript library does it easily and well. Respond with JSON by all means, but don't post JSON, HTTP is a lot easier.
Edit: after writing out the Helpers bit above I realised it would be more helpful as a gem.
Looks like the ability to do post :update, '{"some": "json"}' was added to the internal ActionPack test_case.rb used by rspec in this commit:
https://github.com/rails/rails/commit/5b9708840f4cc1d5414c64be43c5fc6b51d4ecbf
Since you're using Sinatra I'm not sure the best way to get those changes—you might be able to upgrade ActionPack directly, or patch from the above commit.
If you want to look at last_response as JSON, you could try rack-test-json which makes this trivial:
expect(last_response).to be_json
expect(last_response.as_json['key']).to be == 'value'
i am having trouble running my rspec examples in a loop.
describe "GET all providers" do
let(:current_user) { Factory(:user) }
[:twitter, :facebook, :google_oauth2].each do |provider|
before :each do
current_user.confirm!
sign_in current_user
request.env['devise.mapping'] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.add_mock provider, {
:uid => '123456789',
:info => {
:email => current_user.email
}
}
end
it 'should add the authorization' do
get provider # method to create the authorization
authorization = Authorization.where(:provider => request.env["omniauth.auth"][:provider], :uid => request.env["omniauth.auth"][:uid]).first
current_user.authorizations.should include authorization
end
end
end
currently these examples all pass. the problem though is that current_user is a new user instance through each iteration of the loop, despite memoizing the current_user method. so if i add a test for current_user.authorizations.count.should == 3 it fails.
this became less of needing to actually test it, and more understanding why it isnt behaving how i expect. shouldn't let(:current_user) { Factory(:user) } persist the same user instance across all examples?
Here is a gist I came up with that might help you understand let and let!:
https://gist.github.com/3489451
let memoizes the return value within each it example, but executes the block every time it is called for the first time in the example.
For example, if you call current_user the first time in an it example block, the { Factory(:user) } block is executed. Calling current_user a second or any subsequent time within the same it example block does not execute the { Factory(:user) } block; the return value is memoized.
When running functional tests on my controller code in a Rails 3 project, I have a fatal error; the params variable contains controller and action, and ActiveModel is not happy about it:
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: controller, action
/Users/phooze/.rvm/gems/ruby-1.9.3-p0/gems/activemodel-3.2.1/lib/active_model/mass_assignment_security/sanitizer.rb:48:in `process_removed_attributes'
/Users/phooze/.rvm/gems/ruby-1.9.3-p0/gems/activemodel-3.2.1/lib/active_model/mass_assignment_security/sanitizer.rb:20:in `debug_protected_attribute_removal'
/Users/phooze/.rvm/gems/ruby-1.9.3-p0/gems/activemodel-3.2.1/lib/active_model/mass_assignment_security/sanitizer.rb:12:in `sanitize'
/Users/phooze/.rvm/gems/ruby-1.9.3-p0/gems/activemodel-3.2.1/lib/active_model/mass_assignment_security.rb:228:in `sanitize_for_mass_assignment'
/Users/phooze/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.1/lib/active_record/attribute_assignment.rb:75:in `assign_attributes'
/Users/phooze/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.2.1/lib/active_record/base.rb:495:in `initialize'
/Users/phooze/Documents/rails-app/app/controllers/credentials_controller.rb:40:in `new'
The application call is to the "new" method (where the error is occurring), the code is:
# Credential#create (POST)
def create
#credential = Credential.new(params)
# ... controller continues
end
Finally, my test case:
test "should create credential" do
assert_difference('Credential.count', 1) do
post :create, { :fid => "foobarbaz", :credentials_hash => "f00ba7f00ba7", :uid => "10023", :cid => "342" }
end
assert_response :created
end
Changing my controller code to a "separate" parameter hash containing ONLY the fid, credentials_hash, uid, and cid makes it work. I'm pretty sure Rails is trying to be "nice" and provide me with addtional values for testing, but it seems to be causing problems.
Any recommendations on how to solve this?
Looks like you have set config.active_record.mass_assignment_sanitizer = :strict
in your test environment only, but not in development or production, because params always contains controller and action, in any environment.
I think the best-practice recommendation here is to always use form_for, so that you'd have your credentials in params[:credential], or, indeed, do params.slice(:fid, :uid, etc).