Rails - Two controllers or adding actions? - ruby-on-rails

Designing a web app with a admin section and a public facing section. It feels like having a public facing controller just for "index" and "show" is a bit redundant. All the suggestions I've read suggest a namespace for admin, which is fine. I just wonder if I should have one controller with an addition action, say "list_public" or something like that.
I'm new with Rails, so maybe I'm just concerned about nothing. I just don't like the idea of having all these controllers, views, helpers with the same name scattered all over my project directories.
Anyone have any insight to this? Thanks in advance.

I would say having both controllers (one public, and one admin) is the best solution.
Now what you could do is have both the controllers call the same method that does the related actions in the actions.
class MyController < ApplicationController
def show
MyModel.do_all_sorts_of_stuff
end
end
class Admin::MyController < ApplicationController
def show
MyModel.do_all_sorts_of_stuff
# Admin only stuff goes here
end
end

As Matt said, but you can also do this:
class MyController < ApplicationController
def show
MyModel.do_all_sorts_of_stuff
end
end
class Admin::MyController < MyController
def show
super
# Admin only stuff goes here
end
end
This means that you can just focus on the more specialised cases for Admin::MyController rather than repeating code.

Related

Create an "includable" Rails controller action within helper

Is it possible to make an includable controller action within a Rails Helper through an included block? I'm thinking something like this:
module XablauHelper
included do
def my_shared_action
true
end
end
end
Already tried doing it through class.eval block and through using like a class method i.e. self.my_shared_action but no success, I have already found a solution that is making a parent controller with the desired shared actions and inheriting from it, but for the sake of modular design I would like to make it a more "global" approach, so I could gemify my solution and reuse code, any suggestions that doesn't use inheritance?
Adding controller actions in a helper is probably the wrong choice, as these methods are intended for your views.
Consider using controller concerns instead, and including them where required. For example:
# in app/controllers/concerns/useful_functions_concern.rb
module UsefulFunctionsConcern
extend ActiveSupport::Concern
included do
rescue_from SomeException, with: :handle_access_denied
end
def useful_method
# ...
end
protected
def handle_access_denied
# ...
end
end
# in your controller
class XyzController < ApplicationController
include UsefulFunctionsConcern
def index
useful_method
end
end
Where common controller actions can be shared and the controllers have something in common e.g. they are all API controllers, also consider using inheritance to achieve this. For example:
# parent controller
class ApiController < ApplicationController
def my_shared_action
end
end
class SpecificApiController < ApiController
end

Best practice to make model accessible throughout app

I'm in the process of creating my own simple blog application and I want to include a 'latest posts' section on the sidebar, so my posts model needs to be accessible by the entire app. I'm looking for the best way of doing so.
I'm thinking a before_filter in the application controller followed up a private method to call the scope I have:
class ApplicationController < ActionController::Base
before_filter :latest_news
private
def latest_news
#latest = News.latest.limit(5)
end
end
Is this the best way?
Instead of a before_filter, I'd recommend using a lazy-load approach that does basically the same thing.
class ApplicationController < ActionController::Base
helper_method :latest_news
def latest_news
#latest_news ||= News.latest.limit(5)
end
end
This way you can call latest_news from any controller or view (which is what the helper_method macro does for you) and then it'll load it if it's not loaded already the first time it's called and any subsequent calls will be cached. This is a pretty common pattern for getting things like the current user record, etc.

How to reuse the rendering actions from nested controllers in Rails?

I have a question regarding the reuse of code among controller actions. I think it is a fairly standard situation, so I am interested in what's the best practice in Rails.
Let's say I have a films resource with a corresponding FilmsController, which has a nested resource comments served by CommentsController. The nested resource can be rendered on its own using its index and show actions. However, it should also be possible to render the comments embedded in the corresponding film page.
Now, the question goes, what is the best way to reuse the code from CommentsController within FilmsController.show?
1) Force the CommentsController.index to render to a string and then pass it in a variable to the film view?
Or 2) call the CommentsController.index directly in the film view as a kind of "partial", executing the database queries from there?
Or 3) create a separate method in CommentsController responsible for the database handling, call it from both CommentsController.index and FilmsController.show, and use the corresponding view in both the places, too?
To me the options 1) and 2) seem a bit messy, while 3) is not modular and involves some repeating of code. Is there any better way to accomplish this?
Thanks a lot!
Now, the question goes, what is the best way to reuse the code from CommentsController within FilmsController.show?
You could move the shared controller logic into a inside your application controller (or a lib and require it appropriately), a la:
class ApplicationController < ActionController::Base
def foo
#foo = "foo"
end
end
Comments Controller:
class CommentsController < ApplicationController
before_filter :foo, :only => [:index]
def index
end
end
Films Controller:
class FilmsController < ApplicationController
before_filter :foo, :only => [:show]
def show
end
end
For repeated view logic you can move that to a common folder, say your_app/app/views/shared/_foo.html.erb and render that appropriately.
Another option is to place the relevant code into an external module:
lib/mymodule.rb
module MyModule
def foo
end
end
And then you can include the module inside your controller or anywhere you want access to your foo method.
class CommentsController < ApplicationController
include MyModule
def index
foo()
end
end

Where should I store common function at?

I have three models.
users_controllers.rb
communities_controller.rb
community_tipics_controller.rb
I'm using the function called check_digit
def checkdigit
(transaction)
end
and I'm placing this in all the controllers.and calling it by before_filter.
But I think I'm wasting because I'm just pasting exactly the same code above to all of the controllers.
Where am I supposed to put it if my controller is using it in common?
Should I put it in controllers/application_controller.rb?
There are several ways of doing this , some possible ways are (If I'm to do this)
1st method
If this is a simple method used by controllers
inside application_controller.rb
private
def checkdigit
(transaction)
end
2nd method
if your function is used by a specific category , (this is normally I do very often), create a separate controller and have your all other controllers inherited by it
Ex: if your method used only my admins, and assuming you have some more methods like that
class AdminController < ApplicationController
layout 'admin'
private
def checkdigit
(transaction)
end
end
and
class UsersController < AdminController
end
3rd method
If your method is/will used by models/controllers etc.. consider making it a module
module CommonMethods
def checkdigit
(transaction)
end
end
class UsersController < ApplicationController
include CommonMethods
end
HTH
You can put it in helpers/application_helper.rb
You are correct, all common methods that all controllers need should be stored in the ApplicationController.
Furthermore, you should also keep common logic between all controllers in this controller.
Edit:
If they are just helpers, then you would put them where the helpers go, see the answer by #simone.

Rails 3 - how to organize / split up bloated controllers?

I've been working on a CMS app to sharpen up my skills and the controllers are getting quite bloated with the definitions. I know it's possible to store stuff in lib/whatever.rb and then use require and include, but that doesn't quite work with controllers - at least, in my case, where I have before_filters.
Without the definitions right in the controller, before_filters refuse to work.
Do all the defs HAVE to go in the controller or is there a way to take them out? (They are specific to that controller so they can't go in application controller.
You can do a lot of things with mixin modules that will add behavior to an existing controller, or you can try and come up with a class hierarchy that will allow the controllers to inherit the required methods from their parent class.
In most applications I sub-class ApplicationController at least once in order to enforce some standards in certain contexts. For instance, all controllers relating to a Project would inherit from ProjectController::Base:
class ProjectController::Base < ApplicationController
before_filter :must_be_logged_in
before_filter :load_project
protected
def load_project
#project = Project.find(params[:project_id] || params[:id])
rescue ActiveRecord::RecordNotFound
render(:template => 'not_found')
end
def must_be_logged_in
# ...
end
end
The augmentation-plugin (it's rather a snippet) could be a solution for you.
What it does (add some methods to Object/Module)
class ::Object
def self.augment(*mods)
include *mods
mods.each {|mod| class_eval &mod.augmentation }
end
end
class ::Module
def augmentation(&block)
#augmentation ||= block
end
end
What it allows you to do
# app/controllers/your_controller.rb
class YourController
augment YourController::Stuff
...
end
# app/controllers/your_controller/stuff.rb
module YourController::Stuff
augmentation do
before_filter :something
def something
...
end
end
end
You need to make sure that subfolders of folders in /app are included in Rails' autoload paths.

Resources