Rails ActionController::TestCase how to set the controller class explicitly - testing

I have a Controller Test Class file that differs from the name of the original Controller Class
class MyController < ApplicationController
end
class MyControllerNotLoggedTest < ActionController::TestCase
end
When I run the tests I have this error:
RuntimeError: #controller is nil: make sure you set it in your test's setup method.

In Rails 6 looks like it is like this:
class MyControllerNotLoggedTest < ActionController::TestCase
tests MyController
end
https://www.rubydoc.info/docs/rails/4.1.7/ActionController/TestCase#label-Controller+is+automatically+inferred

Related

What is Base in Rails?

The ActiveRecord and ActionController have ::Base attached to it. I googled for this but still couldn't find an explanatory answer. I am curious to know how they exactly work.
You go to GitHub and then press t and then type Base.
You will find classes like ActiveRecord::Base.
The double colon is a scope operator, and in this says that we want the class Base in the module ActionController.
module ActionController
class Base
# ... implementation
end
end
module ActiveRecord
class Base
# ... this is a different class than ActionController::Base
end
end
class MyController < ActionController::Base
# class that inherits from class Base in module ActionController
end
class MyModel < ActiveRecord::Base
# class that inherits from class Base in module ActiveRecord
end

Are scopes in rails class or instance methods?

This is a question from a rails noob trying to understand concerns and scopes.
I always thought scopes were class methods in rails but then the other day I saw this code from DHH:
module Visible
extend ActiveSupport::Concern`
module ClassMethods
def visible_to(person)
where \
"(#{table_name}.bucket_id IN (?) AND
#{table_name}.bucket_type = 'Project') OR
(#{table_name}.bucket_id IN (?) AND
#{table_name}.bucket_type = 'Calendar')",
person.projects.pluck('projects.id'),
calendar_scope.pluck('calendars.id')
end
end
end
So the way the visible method is used is like so:
current_account.posts.visible_to(current_user)
This is what is confusing me. Self here is a collection of posts so we are acting on instances whereas the visible method seems to be meant to be used as a class method. Isn't david trying to call a class method as a dynamic scope? Could someone please clarify?
Class methods on classes which inherit ActiveRecord::Base can be used also as scopes (on ActiveRecord Relation objects).
Since the module Visible was meant to be mixed into a model which inherits ActiveRecord::Base, its class method visible_to can be used also as a scope.
If this did not clear the issue, you can implement a scope which gets all adult users (age > 20) in the following ways:
class User < ActiveRecord::Base
scope :adult, lambda { where("age > ?", 20) } # with a scope
class << self
def adult # with class method
where("age > ?", 20)
end
end
end
And use it exactly the same with User.adult

Helpers in controller - Rails 3

I migrated from rails 2.x to 3.x. Now when calling a controller method throws
undefined method `my_helper_method' for nil:NilClass
MyController.rb
class MyController < ApplicationController
def foo
#template.my_helper_method
end
end
MyControllerHelper.rb
class MyControllerHelper
def my_helper_method
puts "Hello"
end
end
ApplicationController
class ApplicationController < ActionController::Base
helper :all
end
How to get this working?
This is actually answered in another SO post: Rails 3: #template variable inside controllers is nil
Essentially, you can replace #template with view_context
#template is an object, in your case nil. If this object doesn't has the method (my_helper_method) in it, you cannot call it (especially not if it is nil).
Methods defined in helpers are called like regular methods. But not in controllers, they are called in views. Your helper :all just makes all helpers available to the views.
So, in your view: my_helper_method :arg1, :arg2
IF you need a method for your object (#template), you need to give your object this method.
Example:
class Template < ActiveRecord::Base
def my_helper_method
# do something on a template instance
end
end
class MyController < ApplicationController
def foo
#template = Template.first
#template.my_helper_method # which actually isn't a helper
end
end
What helpers do:
module MyHelper
def helper_method_for_template(what)
end
end
# in your view
helper_method_for_template(#template)
Mixing in a helper (be aware of having a mess in your code when mixing view helpers with views and models)
class Template < ActiveRecord::Base
include MyHelper
# Now, there is #template.helper_method_for_template(what) in here.
# This can get messy when you are making your helpers available to your
# views AND use them here. So why not just write the code in here where it belongs
# and leave helpers to the views?
end

how to access a method in a model from a controller in rails

I want to put logic in the model rather than controller.
class UsersController < ApplicationController
def somemethod
d = User.methodinmodel
end
end
class User < ActiveRecord::Base
def methodinmodel
"retuns foo"
end
end
I get an error that there is no methodinmodel for the User model.
Why?
If you want to be able to call methodinmodel on the User class in general rather than a specific user, you need to make it a class method using self:
class User < ActiveRecord::Base
def self.methodinmodel
"returns foo"
end
end
Your current method definition would only work if you called it on a user:
#user = User.create!
#user.methodinmodel # Works.
User.methodinmodel # Doesn't work.
Using the new implementation using self would allow you to call it like:
User.methodinmodel # Works.

setting the "view-name" of a controller

I would like to centralize similar actions of some controllers and wrote a controller from which the other controllers inherites. This works fine.
# calling Configurations#index will render configurations/index.html.erb
# while 'configurations' being the internal controller_path used to look for the view
class ConfigurationsController < EditorController
end
class EditorController < ApplicationController
def index
render 'index'
end
end
But now I would like to centralise the views to the "base"-controller one's, so if an inheriting controller is called, the controller_path used should be the base-controller one's.
Is there a way, to rewrite a controllers name or controller_path?
I looked at the source of AbstractController::Base and found that (line 90)
def controller_path
#controller_path ||= name.sub(/Controller$/, '').underscore unless anonymous?
end
So I just need to set #controller_path from my base-controller don't I ? This doesn't change anything:
#just does the same as above
class EditorController < ApplicationController
#controller_path = 'editor'
def index
render 'index'
end
end
So is there a way to set the controller_path manually?
great thanks in advance!
damn I found it on my own!
I just overwrote the controller_path method:
class EditorController < ApplicationController
def controller_path
'editor'
end
#...
end
this will ever use the view-folder 'editor' for any inheriting controller.