I have a Configurable model:
# /models/configuration.rb
class Configuration < ActiveRecord::Base
end
When I reference Configurable in my pages_controller, it works fine:
class PagesController < ApplicationController
def search
#description = Configuration.find_by_name('description') || nil
end
end
But when I reference it in my application_controller.rb, like so
class ApplicationController < ActionController::Base
def get_menu
#menu = Configuration.where(name: 'menu') || nil
end
end
I get the error undefined method 'where' for ActiveSupport::Configurable::Configuration:Class. How can I prevent my Configuration model and ActiveSupport::Configurable::Configuration:Class from colliding like this, or reference my Configuration model directly?
Thanks in advance!
You need to prefix it
::Configuration.where(name: 'menu')
Notice the :: before the class name. They force the interpreter to use the Configuration class in the main namespace, rather than one in the ActiveSupport namespace.
Related
Rails 3.2
In my controllers/admin/accounts_receivables_contoller.rb, I have:
class Admin::AccountsReceivables < Admin::ApplicationController
def index
...
end
and in one of the views, I have:
= link_to admin_accounts_receivables_path
In my config/routes.rb, I have:
namespace :admin do
resources :accounts_receivables do
collection do
get 'admin_report'
get 'customer_report'
post 'process_invoices'
end
end
end
rake routes, produces:
admin_accounts_receivables GET admin/accounts_receivables(.:format) admin/accounts_receivables#index
However, when I click on the link, I get (in the browser, but no entry in the log file):
uninitialized constant Admin::AccountsReceivablesController
I do not have a corresponding AccountsReceivable model, as I don't need it.
Any ideas?
The class should be named AccountsReceivablesController and you should nest the class explicitly instead of using the scope resolution operator so that it has the correct module nesting:
module Admin
class AccountsReceivablesController < ApplicationController
def index
# ...
end
end
end
When you use the scope resolution operator class Admin::AccountsReceivablesController - the module nesting is resolved to the point of definition which is Main (the global scope) and not Admin. For example:
module Admin
FOO = "this is what we expected"
end
FOO = "but this is what we will actually get"
class Admin::AccountsReceivablesController < Admin::ApplicationController
def index
render plain: FOO
end
end
See The Ruby Style Guide - namespaces.
class Admin::AccountsReceivables < Admin::ApplicationController
should be...
class Admin::AccountsReceivablesController < Admin::ApplicationController
I have two models that share the behavior. Both Post and Comment can have reactions.
# ./app/models/post.rb
class Post < ApplicationRecord
has_many :reactions, as: :reactionable
end
# ./app/models/comment.rb
class Comment < ApplicationRecord
has_many :reactions, as: :reactionable
end
When I decorate them, I end up with a lot of exact same methods.
# ./app/decorators/post_decorator.rb
class PostDecorator < ApplicationDecorator
delegate_all
def reactions_total_count
object.reactions.count
end
def reactions_type(kind)
object.reactions.collect(&:reaction_type).inject(0) {|counter, item| counter += item == kind ? 1 : 0}
end
def likes_count
reactions_type('like')
end
def hearts_count
reactions_type('heart')
end
def wows_count
reactions_type('wow')
end
def laughs_count
reactions_type('laugh')
end
def sads_count
reactions_type('sad')
end
end
# ./app/decorators/comment.rb
class CommentDecorator < ApplicationDecorator
delegate_all
def reactions_total_count
object.reactions.count
end
def reactions_type(kind)
object.reactions.collect(&:reaction_type).inject(0) {|counter, item| counter += item == kind ? 1 : 0}
end
def likes_count
reactions_type('like')
end
def hearts_count
reactions_type('heart')
end
def wows_count
reactions_type('wow')
end
def laughs_count
reactions_type('laugh')
end
def sads_count
reactions_type('sad')
end
end
I want it to look something like this, but don't know where to put the files, and exactly which technique I should use (include vs. extend).
# ./app/decorators/base.rb
module Base
# methods defined here
end
# ./app/decorators/post.rb
class PostDecorator < ApplicationDecorator
delegate_all
include Base
end
# ./app/decorators/comment.rb
class CommentDecorator < ApplicationDecorator
delegate_all
include Base
end
Please advise. I know there is a better approach that I just can't seem to get right.
First of all, I would figure out a better name for the included module. It could be treated as a role, using which you would enrich classes. This role would have declared a bunch of *_count methods that counts smth in reactions.
So I would name it ReactionsCountable and additionally put it into namespace to distinguish from the decorators: Roles::ReactionsCountable.
Then I would put it into:
/app/decorators
/roles
/reactions_countable.rb
/comment.rb
/post.rb
Other soulution would be to use classic inheritence. Here the Base name would make sense IMO:
class BaseDecorator < ApplicationDecorator
# declare `*_count` methods here
class PostDecorator < BaseDecorator
class CommentDecorator < BaseDecorator
I figured it out with Maicher's answer.
If a CommentDecorator is inside of ./app/decorators/comment_decorator.rb, and we want to include a module, ReactionablesCountable, then we need to create a file inside of ./app/decorators/roles/reactions_countable.rb that has module nesting which reflects the path to the file. For example, the first constant in the include, (Roles) points to the folder Rails will look for it, the second (ReactionsCountable), is the name of the file.
The module needs to be nested within this file as well. I've shown it below.
module Roles
module ReactionsCountable
# methods defined here.
end
end
I am trying to make my rails code a bit nicer.
I have this:
class MyController < ApplicationController
before_action do
# #variable_defined_else_where is an object w/ accessors
#variable_defined_else_where.some_value = "string"
end
end
I would like to do this some how get to here:
class MyController < ApplicationController
variable_defined_else_where(some_value: "string")
# or
variable_defined_else_where.some_value = "string"
# or
some_method "string"
end
I looked at the rails actionview code, for "layout" which has a similar syntax-ness
class MyController < ApplicationController
layout "string"
end
However, it declares a method in the class, I need to modify a
#variable_defined_else_where
which then controls how several bits of helpers behave
module MyHelper
def do_if_that
if #variable_defined_else_where == "string"
# do so and so
end
end
end
Does anyone have any suggestions on how I can get to syntaxically happy-ness?
Since before_action executes in the instance context, your variable-in-question is an instance variable, which means it's only set on the instance of the controller (i.e., during the request lifecycle). On the other hand, layout is most likely setting a property on the controller class itself.
If your variable could be moved to the class-level without compromising thread-safety, you could make it a class attribute and set it directly like:
class MyController < ApplicationController
##my_variable = 3
def test
##my_variable # returns 3
end
end
But if you don't like how # signs look, maybe that's not better :)
Here's another option, which just wraps your before_action definition inside a class method:
module SetsSomeVariable
include ActiveSupport::Concern
module ClassMethods
def set_variable(value)
self.before_action do
#my_variable = value
end
end
end
end
# ...
class MyController < ApplicationController
include SetsSomeVariable # this could be in ApplicationController
set_variable 'string'
end
I'm trying to share a session variable in both the controllers, the views and the model.
With the following code, it is working in the controllers and in the views :
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :best_language_id
# Returns the ID of the language to use to display the description.
def best_language_id
#best_language_id ||= session[:best_language_id]
#best_language_id ||= current_project.default_language.id
return #best_language_id
end
end
But I can't call it from the model.
I would like to be able to call best_language_id either in the controllers, views and in one model, to get a fallback of the best_language_id if a translation is not found.
Example in my model (not working) :
class Point < ActiveRecord::Base
# Retuns the attached word in the given language if exists.
# Otherwise, falls back on another translation
def word(preffered_language_id)
word = Word.find(:translation_id => self.translation_id, :language_id => preffered_language_id)
if word.blank?
word = translations.where(:translation_id => self.translation_id, :language_id => best_language_id)
end
return word
end
end
I know that model should not include applicationcontroller method calls, but how is it possible to share my best_language_id accross controllers and model ?
Edit : using i18n is not the question here. Translations are not fixed string but variables in a database.
Thanks for helping !
In your rails app, you have a base module in config/application.rb. It should be named after your application. Let's say its called MyApp. What you could do is define two methods like this:
module MyApp
...
def self.language_id=(value)
#language_id = value
end
def self.language_id
#language_id ||= 'en' # default vaule
end
...
end
Then, in app/controllers/application_controller.rb add a before_filter like this:
before_filter :language
def language
MyApp.language_id = session[:language_id] if session[:language_id]
end
Then, from all over the app, you can access the value via
MyApp.language_id
Needless to say that the approach is not thread safe so don't use it in a threaded environment.
I would suggest you switch the situation around, store the best_language_id in the model as a class accessor, then you can set and get it from your controllers and it will still be available in the models.
class Point < ActiveRecord::Base
cattr_accessor :best_language_id # to store the variable
end
# Persist the content of that variable at the start of every action
class ApplicationController < ActionController::Base
before_filter :set_best_language
def set_best_language
Point.best_language_id = session[:best_language_id]
Point.best_language_id ||= current_project.default_language.id
end
end
# Use the variable in a controller
class SomeOtherController < ActionController::Base
def show
#best_language = Language.find(Point.best_language_id)
...
end
end
# Use the variable in a model
class SomeOtherController < ActiveRecord::Base
def some_method
best_language = Language.find(Point.best_language_id)
...
end
end
I have several controllers that are in a module:
class SoapTest::DashboardController < ApplicationController
class SoapTest::TestCasesController < ApplicationController
etc.
I want to be able to check if a user has certain permissions for a module, and since I don't have a "parent" controller where the above ones inherit, i thought to put the check in a before filter in applications. But I can't seem to get the module name:
in application controller, i have:
before_filter :check_company_features
def check_company_features
puts controller_name
end
but controller_name just returns "dashboard". I need to get the "SoapTest" clause
Be attention, what you currently call modules actually are namespaces.
The reason why controller_name returns only the class name (and not the fully qualified name) is because Rails explicitly strips the namespaces. You can get them by calling the Ruby #name method on the controller class.
class SoapTest::DashboardController < ApplicationController
before_filter :check_company_features
def check_company_features
puts controller_name
# => "dashboard_controller"
puts self.class.name
# => "SoapTest::DashboardController"
end
end
There are several String inflection methods you can call on the #name to get the formatted version.
However, I strongly encourage you to use a namespaced main controller.
Instead of using
class SoapTest::DashboardController < ApplicationController
you can extend a SoapTest::ApplicationController
class SoapTest::ApplicationController < ApplicationController
before_filter :check_company_features
def check_company_features
# ...
end
end
class SoapTest::DashboardController < SoapTest::ApplicationController
end