Wrong model stub when testing controllers which using inherited_resources - ruby-on-rails-3

I'm new to RSpec and my controllers're using inherited_resources, I have this mock/stub setup like:
describe MarketsController do
def mock_market(stubs={})
#mock_market ||= mock_model(Market, stubs).as_null_object
end
describe "GET index" do
it "assigns all markets as #markets" do
Market.stub(:all){ [mock_market] }
get :index
assigns(:markets).should eql([mock_market])
end
end
end
And this spec fails because there's nothing in the assigns(:markets). After I added:
class MarketsController
def index
#markets = Market.all
end
end
it'll pass so I guess that's because the inherited_resources doesn't call Market.all to get all of the Market instance and thus bypass the stub for Market.stub(:all). The index method I added above is obviously redundant and shouldn't exist at all, so the question is, without call Market.all explicitly, what should I do in my spec to complete the tests? Thanks in advance!

If I am reading the code correctly, inherited_resources first tries to use Market.scoped if it exists. So do you have a scoped scope?

Related

get all records via operation and show in view

I have trouble with trailblazer when setting up a simple show all Things view.
operation
class Thing < ApplicationRecord
class ShowAll < Trailblazer::Operation
include Model
model Thing, :all #why :all is not working here?
def process
end
end
end
controller
class PageController < ApplicationController
def index
run Word::ShowAll
end
end
why is :all not working for getting all Things from the db but :find works to get one via its id?
The best place to ask TRB questions is actually on Github channel.
I'm not sure where you found that example, as it is not supposed to work AFAIK, :find is a shortcut I believe, I've never actually used it.
All your logic should be defined inside the process method. http://trailblazer.to/gems/operation/1.1/api.html#process
Having said that, trying to get all records without some kind of pagination is a really bad idea, unless you are 100% sure that your table won't grow beyond several dozen records. Unless you know you don't have a large load. So to define that kind of shortcut is dangerous.
Calling Trailblazer::Model#model as you're doing there is just a shortcut for overriding the TrailBlazer::Operaration#model! method. So what you seem to want to do is:
class Thing < ApplicationRecord
class ShowAll < Trailblazer::Operation
def model!(params)
Thing.all # add any filtering or pagination here
end
end
end
And in your controller call present instead of run so that it sets up the model but doesn't call the process method of the operation.
class PageController < ApplicationController
def index
present Word::ShowAll
end
end

Redmine: extend controller action in plugin

Need some help in plugin development.
I've created hook in user/edit form view, added ballance_amount to form and have "ballance_amount"=>"1".
How can I extend default update action in user controller?
In base.class_eval do I've added alias_method_chain :update, :ballance
In InstanceMethods:
def update_with_ballance
ballance.amount = params[:user][:ballance_amount].to_f #I have ballance association
end
And get this:
NameError (undefined local variable or method `params' for #<User:0x007f972e9379d0>):
app/controllers/users_controller.rb:144:in `update'
How can I fetch params?
You should be able to make use of the mass-assignment code in the Redmine itself. Line 135 in the UsersController should handle provide you with a simple entry point for your extension, if balance_amount is considered a safe_attribute. To achieve that, add a patch like the following to the User model:
module RedmineBalancePlugin::UserPatch
def self.included(base)
base.class_eval do
safe_attributes 'balance_amount'
include InstanceMethods
end
end
module InstanceMethods
# This method is indirectly called when creating or updating a User
def balance_amount=(amount)
balance.amount = amount
end
# This could be useful in your view patch, but maybe not
def balance_amount
balance.amount
end
end
end
User.send(:include, RedmineBalancePlugin::UserPatch)
If this example does not help, it would be helpful, if you could provide more code fragments - e.g. the complete patch to the UsersController, to make it easier to reproduce and analyse the issue.

How to rescue custom exceptions coming from a middleware in Rails 3.2?

I have a Rails 3.2 application that uses Apartment, which is used as a middleware. Apartment throws an Apartment::SchemaNotFound exception and there is no way to rescue it with rescue_from from the ApplicationController. I thought I'd use config.exceptions_app as described in point #3 in this blog post, but I can't set the router as the exception app, I assume I have to create my own.
So the question is: How do I proceed?
We've purposefully left Apartment pretty minimal to allow you the handle the exception itself without really needing any Rails specific setup.
I'd do something similar to what #jenn is doing above, but I wouldn't bother setting a rack env and dealing with it later, just handle the response completely in rack.
It's typical for instance that you maybe just want to redirect back to / on SchemaNotFound
You could do something like
module MyApp
class Apartment < ::Apartment::Elevators::Subdomain
def call(env)
super
rescue ::Apartment::TenantNotFound
[302, {'Location' => '/'}, []]
end
end
end
This is a pretty raw handling of the exception. If you need something to happen more on the Rails side, then #jenn's answer should also work.
Check out the Rack for more details
I had a similar problem with another piece of middleware throwing a custom exception, so I haven't actually looked at Apartment at all, but maybe something like this:
#app/middleware/apartment/rescued_apartment_middleware.rb
module Apartment
class RescuedApartmentMiddleware < Apartment::Middleware
def call(env)
begin
super
rescue Apartment::SchemaNotFound
env[:apartment_schema_not_found] = true # to be later referenced in your ApplicationController
#app.call(env) # the middleware call method should return this, but it was probably short-circuited by the raise
end
end
end
end
Then in your environment:
config.middleware.use(Apartment::RescuedApartmentMiddleware, etc)
To access the env variable you set from ApplicationController or any controller:
if request.env[:apartment_schema_not_found]
#handle
end
Combo of How to rescue from a OAuth::Unauthorized exception in a Ruby on Rails application? and How do I access the Rack environment from within Rails?

How do I stub ::Rails.root in rspec?

I'm writing a gem that can be used both with and without rails. In a few places I use code like
path = Rails.root if defined?(::Rails)
and I want to test this logic with rspec. I have tried stubbing it like
stub(:"::Rails").should_receive(:root).and_return("/rails")
but this does not make defined?(::Rails) evaluate to true.
Even if defined?(::Rails) is evaluated to true, you still need a Rails object to inject the method stub. There might be several ways to do this, following is a example of my preferred approach:
before(:each) do
unless defined?(::Rails)
#mocked_rails_class = true
class ::Rails
end
end
end
it do
::Rails.should_receive(:root).and_return('/rails')
your_method.should == '/rails'
end
after(:each) do
# Clean up the Rails class if it's generated by the test case.
Object.send(:remove_const, :Rails) if #mocked_rails_class
end
I'm not sure if it works on all ruby version, but at least it can work on Ruby 1.9.x.

Why has shoulda controller test assign_to no access to instance variable?

For my Rails 3 application I use FactoryGirl together with shoulda context (1.0.0.beta1) and matchers (1.0.0.beta3) for my functional tests.
My problem: in the code example below, the assign_to test fails because #user - to my surprise - turns out to be nil. In the outer setup block, #user is assigned a valid model instance, but from within the should assign_to statement the instance variable is not accessible. Why is that and what is the correct way to write that test?
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
#user = Factory.create(:user)
end
context "getting index" do
setup do
get :index
end
should assign_to(:users).with([#user])
end
end
I discovered that passing the value as a black miraculously works. However, after digging into the actual AssignToMatcher code, it doesn't seem to make sense why the parameter method wouldn't work while the block method would.
For the sake of the +250 rep I'm investing in this, I'd still like an answer that explains why the param method isn't working (and how to fix it), but until then, at least I have a workaround.
#dblp1, hopefully this works for you too. Here's an example specific to your code:
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
#user = Factory.create(:user)
end
context "getting index" do
setup do
get :index
end
should assign_to(:users).with { [#user] }
end
end
end
(I am pasting as an answer as it is fairly long)
I mocked a bit your test and checked what was the results passed.
Interestingly enough, when I call the matcher #post=null (as I believe in your case). The issues I think (after a while of investigation), it coming from the the order the setup do block is called and the fact that the variables defined in one context are not visible in the nested context.
modified class
context "as admin" do
setup do
#post = Post.new
puts "Step 1 - inside setup do"
puts #post.class
end
puts "Step 2 - outside setup do 1"
puts #post.class
context "getting index" do
setup do
get :index
end
puts "Step 3 - calling shoulda"
puts #post.class
should assign_to(:posts).with([#post])
#should assign_to(:posts).with { [#post] }
end
end
And the results in the console
ruby -I test test/functional/posts_controller_test.rb
Step 2 - outside setup do 1
NilClass
Step 3 - calling shoulda
NilClass
Loaded suite test/functional/posts_controller_test
Started
Step 1 - inside setup do
Post
So the setup cycle is called at the end (and not at the beginning) and then your is Nil when passed to the matcher.
Even if I remove the first setup do does not work pretty well.
Step 1 - inside setup do
Post
Step 2 - outside setup do 1
Post
Step 3 - calling shoulda
NilClass
Finally, putting the post in the inner context
Step 3 - calling shoulda
Post
If you call #user = Factory.create(:user) directly inside the "getting index" context, I believe it will work.
When you are working with indexes you should use the plural of the instance variable.
#users rather than #user
You should also populate it as an array.
Finally, Shoulda matchers should start with "it" and be contained in braces, at least in the RSpec world, which is what I use. Not sure if this is the case with Test::Unit or whether your formatting above will work.
Try something like this.
class UsersControllerTest < ActionController::TestCase
context "as admin" do
setup do
#user = Factory.create(:user)
end
context "getting index" do
setup do
#users = Array.new(3) { Factory(:user) }
get :index
end
it { should assign_to(:users).with(#users) }
end
end