i am beginning to create a module that has shared functionality in the controllers of my rails app. I am trying to include a record find in another controller that requires that record. I use friendly id to slug instances of a corp_page, trying to find the corp_pages record the controllers gives me this error,
ActiveRecord::RecordNotFound at /admin/corporate_pages/home/corporate_panels
Couldn't find CorporatePage without an ID
The code,
module CorporateConcern
extend ActiveSupport::Concern
included do
before_filter :get_corp_page
before_filter :get_corp_panel
end
def get_corp_page
#corp_page = CorporatePage.friendly.find(params[:id])
end
def get_corp_panel
#corp_panel = CorporatePanel.where(id: params[:id]).first
end
end
class Admin::CorporatePanelsController < AdminController
include CorporateConcern
......
end
class Admin::CorporatePagesController < AdminController
include CorporateConcern
end
thanks in advance
Related
I'm relatively new to Rails and am working on creating a simple user authentication system to get to grips with how Rails works.
I'm currently at the point where I'd like to create some methods that I can use in my controllers like so:
is_logged? # => true
and
current_user_id # => 6
These would be used to interact with sessions, mainly so I'm not repeating myself in the controller.
Where would I define these functions and how would I include them in a controller?
Thanks a lot in advance for any help.
Method 1
You can define these method in helper files, inside app/helpers/my_module.rb. You can create a module there, put all the methods inside of it, and then include the modules in your control to use these method.
module MyMoule
def is_logged?
...
end
end
Then in you class include the module
class MyClassController < ApplicationController
include MyModule
def my_method
#Use it like this
logged_in = MyModule.is_logged?
end
end
Method 2
If you using session related stuff you can always put them inside application_controller.rb. And since all your controller will inherit ApplicationController the methods will be available to you.
class ApplicationController < ActionController::Base
def is_logged?
...
end
end
In your other controller you can use them directly.
class MyClassController < ApplicationController
def my_method
logged_in = is_logged?
end
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 am looking to write certain methods for processing strings, and other tasks that take place in numerous of my controllers. I know its bad practice to include helpers in your controller, so I was just wondering, where is the best place to put application wide methods used in controllers?
I realize some of you will say to put them in models, but you have to realize that not all my controllers have an associated model. Any and all input would be appreciated.
I tend to put them into helpers. The fact that they are included in views
automatically haven't been a problem for me. You can also place them into
something like app/concerns/ or lib/
I don't like cluttering ApplicationController with private methods
because this often becomes a mess.
Example:
module AuthenticationHelper
def current_user
#current_user # ||= ...
end
def authenticate!
redirect_to new_session_url unless current_user.signed_in?
end
end
module MobileSubdomain
def self.included(controller)
controller.before_filter :set_mobile_format
end
def set_mobile_format
request.format = :mobile if request.subdomain == "m"
end
end
class ApplicationController
include AuthenticationHelper
include MobileSubdomain
end
If you need to use a method in the application scope then I would suggest that you keep those methods inside the application controller and in order to use them inside views.. declare those as helper methods.
For example,
class ApplicationController < ActionController::Base
helper_method :current_user, :some_method
def current_user
#user ||= User.find_by_id(session[:user_id])
end
def some_method
end
end
I would suggest to put them in lib folder. So for example I have:
lib/utils/string_utils
module StringUtils
def foo
...
end
end
class BarController < ActionController::Base
include StringUtils
end
This demonstrates good methodology called Fat model, Thin controller, in this case we are using Mixins instead of Models to separate logic but idea is same. You want your controllers as simple as possible.
It all depends on your needs. I will provide here 2 examples. Both of them are just a custom libraries, located under lib directory.
First example - "custom string processing"
# lib/filters.rb
module Filters
# Converts value to canonical view
def self.phone(value)
# remove all non-digits
clean_value = value.gsub(/\D/, '')
country_codes = configus.phone.country_codes
area_code = configus.phone.defaults.area_code
case clean_value.length
when 7
"#{area_code}#{clean_value}"
when 11
# remove country code only if phone starts with the allowed country code
if country_codes.include?(clean_value[0].to_i)
clean_value[1..-1]
else
clean_value
end
else clean_value
end
end
# usage
# app/api/phones_controller.rb
class Api::PhonesController < Api::ApplicationController
def exists
if params[:q]
clean_value = Filters.phone(params[:q])
...
end
end
end
Second example - helper for flash messages
# lib/flash_helper.rb
module FlashHelper
def flash_translate(key, options = {})
scope = [:flash, :controllers]
scope += params[:controller].split('/')
scope << params[:action]
t(key, {:scope => scope}.merge(options))
end
end
# app/application_controller.rb
class ApplicationController < ActionController::Base
include FlashHelper
end
# usage
# app/your_controller.rb
class YourController < ApplicationController
def create
#object = Object.new(params[:object])
if #object.save
flash[:success] = flash_translate(:success)
...
end
end
end
Note: do not forget to add lib dir to the autoload paths. In config/application.rb add/modify this line config.autoload_paths += %W(#{config.root}/lib).
So for me the answer is lib directory.
Starting from Rails 4 there is a dedicated folder for it app/controllers/concerns. So you can create a module there and then include it in a specific controller(s) or in ApplicationController if you need it available throughout all your controllers.
In case those methods are used in numerous controllers, I would define them in application_controller.rb. Every controller will inherits from it and will be capable to use any method defined there
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
I have a controller having more than 1000 lines of code.
Right not I am doing Code review for this controller.
I arrange my methods according to the module.
Now I realise that my controller is not easy to maintain and so I want to something like following
class UsersController < ApplicationController
#Code to require files here
#before filter code will goes here
#############Here i want to call that partial like things. following is just pseudo #########
history module
account module
calendar module
shipment module
payment module
####################################################################
end #end of class
this help me so much to maintained the code as when i change history module i am sure that my account module is unchanged.I know CVS but i prefer 50 copies of each module instead 200 copies of my users_controller.rb itself.
P.S. :- I would like Affirmative answer.please don't answer like, you should use different controller for different module.....bla...bla...bla... as it's not possible for me to do so.
EDIT:- My Versions Are
rails -v
Rails 2.3.4
ruby -v
ruby 1.8.6 (2008-08-11 patchlevel 287) [i386-linux]
This should work for you:
app/controllers/some_controller.rb
class SomeController < ApplicationController
include MyCustomMethods
end
lib/my_custom_methods.rb
module MyCustomMethods
def custom
render :text => "Rendered from a method included from a module!"
end
end
config/routes.rb
# For rails 3:
match '/cool' => "some#custom"
# For rails 2:
map.cool 'cool', :controller => "some", :action => "custom"
Fire up your app and hit http://localhost:3000/cool, and you'll get your custom method included from a module.
Assuming from you pseudocode that you are referring to Ruby modules, and not something else, just put all your requires/modules in a separate module and include that or have your UsersController inherit from a base class if you are reusing those files. In the first case you can think of a module as a mix-in and it is designed for exactly the modularity you want.
module AllMyStuff
include History
include Account
...
end
class UsersController < ApplicationController
include AllMyStuff
def new
end
...
end
or you can inherit from a base controller,in this case its probably a reasonable solution.
def BaseController < ActionController
include history
include account
end
def UsersController < BaseController
# modules available to this controller by inheritance
def new
end
...
end
I tried the following method and I have it running, maybe it suits for you:
app/user_controller.rb
require 'index.rb'
class UsersController < ApplicationController
# some other code
end
app/index.rb
class UsersController < ApplicationController
def index
#users = User.all
end
end
MY ENV: rails 3 beta4