Using Multiple Controllers in One View in Rails

multiple controllers in one view (ruby on rails MVC)

  1. Technically, this terminology is somewhat confusing. By default each method in a controller corresponds to a similarly-named view file, so it may be better to word the question as "Is it good practice to render a view that is not the default view?" And the answer is, of course, it depends. It is a technique commonly used to DRY up controller code and if there are advantages to be gained by it, in your application, I would certainly use it. In fact, the controller code generated by the default resource scaffolding in Rails uses it in the create and update methods. I think you could make the argument that anything in Rails core is, if not a best-practice, at least within the limits of sanity.

  2. With that being said, there may be opportunities for improvement. A common way to handle the same thing would be to route your create and update requests to the same controller action and use the same controller view. If that is not feasible, at least be assured that you will not need to redefine the variables. From the official documentation:

Using render with :action is a frequent source of confusion for Rails
newcomers. The specified action is used to determine which view to
render, but Rails does not run any of the code for that action in the
controller. Any instance variables that you require in the view must
be set up in the current action before calling render.

  1. You shouldn't need to do that... Not in this situation, or any other one that I can think of. Any time you see something super hackey like that in Rails is a sign that something probably isn't quite right, and that there are probably better ways to handle the same thing.

Bonus: If you need to go somewhere that already is in charge of setting itself up, and you don't need access to any of the in scope variables, a redirect is probably a better choice. That way, you don't need to re-describe your controller logic in multiple places. Here is an example from your posted code:

    # inefficient and not DRY
@user = User.find(current_user)
@microposts = @user.microposts.paginate(page: params[:page])
render 'users/show'

# does the same thing as above (in this case)
redirect_to users_path

Two controllers for one shared view in Ruby on Rails

I have a similar situation with one of my projects. All the delete views for most controllers are styled the same way, display the same confirmation boxes, and simply renders a predictable display of whatever object is being deleted.

The solution was quite simple and elegant in my opinion. Simply put, what we (the developers) did was create a new directory in app/views called shared and put shared views in there. These could be full template files or just partials.

I would suggest using a shared template (in neither categories nor photos view directories, but rather in the shared directory) and rendering it manually from the view.

e.g. have a method as such in both controllers and a file app/views/shared/photo.html.erb:

def show
@photo = Photo.first # ... or whatever here
render :template => 'shared/photo'
end

This should successfully render the shared template. It is the DRYest route and doesn't have the feeling of pollution you get when using a more-or-less empty view in each controller's view directory just to include a shared partial, as I understand your question is suggesting.

Rails: Combining Multiple Controller Actions with their own Views into a Single View

As I understand it - you want to reuse both the views and the code that populates @post_array and @request_array in your home view. I see these as two different concerns with different solutions:

  • For reusing the views you can use partials. By having partials for the posts feed and the request feed you could reuse the view in the home view.
  • And for reusing the way you populate the @post_array you could try and place that logic in somewhere where your HomeController has access to, ideally your Post model (i.e. Post.feed(current_user, location)) or a service object. Another, hacky way to do this is by placing these methods in the ApplicationController, making them available in all controllers.

Using multiple controllers in one view in Rails

First off, you should put all of the data-storing and data-gathering methods into Resources and Models so they are accessible from all controllers. You can keep the internal data-mutating operations in your individual controllers though. Once you have it organized like this, you could do what Hobo does: create a controller just for the front page, "front_controller" if you will. Here you can display data gathered from all of your models and resources, as well as links to your other controller actions.

These are a few interesting thoughts on better organizing your models and controllers (fat models, skinny controllers is a rule of thumb.
Since you said you are using other API's (like lastfm and twitter), you might want to take a look at this railscasts about creating non ActiveRecord models (models that are not tied to a database)

here is some pseudo code, keep in mind its really only targeted at your question.

#  pseudo code  

class TwitterController < ApplicationController
def index
@services = {
:twitter => TwitterModel.find(:all, ...),
}
end
def update_twitter
TwitterUpdaterClass.update { |twit|
_m = TwitterModel.new
_m.message = twit.msg
_m.from = twit.from
# ..
_m.save
}
end
end

class MyIndexController < ApplicationController
def index
@services = {
:twitter => TwitterModel.find(:all, ...),
:lastfm => LastFmModel.find(:all, ...)
}
end
end

it might be much better to have background-workers update your rest-services instead a controller which you need to invoke every time you want to fetch recent tweets.
here is nice article showing - 6 ways to run background jobs in rubyonrails

  # more pseudo code

class TwitterWorker < BackgrounDRb::MetaWorker
set_worker_name :twitter_worker
def create(args = nil) # instead of TwitterController.update_twitter
TwitterUpdaterClass.update { |twit|
_m = TwitterModel.new
_m.message = twit.msg
_m.from = twit.from
# ..
_m.save
}
end
end

Multiple controllers with one route in rails

You did not post the route for your static controller, but I suspect that it is a similar route to the categories route. The problem is that both of them act like wildcards "eat" all other routes after them. match '/:id' will match everything, and so does your static route (probably).

One solution is to introduce constraints to one of the routes, and place it first.

This can be a regexp:

get '/:id', to: 'content_categories#show', constraints: { id: /category\-[0-9]+/ }

get '/:page_name', to: 'static#show'

You can also do more complex constraints by creating a constraint object.

On the other hand, if you have static routes like this:

get "/admin", to: "static#admin"

Then you should be able to solve the problem by just placing these routes before the any wildcard routes.

How can i use multiple controller with one model?

migration CreatePostTable

class Post < ActiveRecord::Base
attr_accessible :content, :published_at, :status, :title, :type, :user_id
has_many :entity_categories
has_many :entity_pages
end

class RegularPost < Post
end

class SpecialPost < Post
end

In your DB, you only have a Post table and Rails will set automatically the type column to the right class.

Like you could do

puts RegularPost.new.type
# => "RegularPost"

then you create regular_posts_controller, spcial_posts_controller etc and you are good to go. Is it what you were looking for?

Ruby on Rails: How to have multiple controllers for one table AND multiple models

There's really no need for a model here, at all. This isn't what ORMs are for. What you should be doing is just running raw SQL against the database, and iterating over the results. Consider doing something like this: https://stackoverflow.com/a/14840547/229044

Two views, two controllers, one model, different re_direct in each controller based on view

You can get referer path and redirect action to this path:

# comments_controller.rb

def comment_create_redirect_path
return root_path if request.try(:referer).blank?
URI(request.referer).path
end

Share the same piece of data in multiple controllers and views

Simple Solution:

  • Normally, I just put these into application_controller.rb as a before_action.

Example

# app/controllers/application_controller.rb
before_action :set_sidebar_resources
# ...

private

def set_sidebar_resources
@sidebar_archives = Archive.all
@sidebar_categories = Category.all
end

Modular Solution:

  • Simple solution above works great until you define more and more methods and other global controller logic into ApplicationController, and then the file becomes too big to manage. The following is a less conventional approach favouring more of manageability rather than simplicity.

Example

# app/controllers/application_controller.rb
include WithSidebar

# app/controllers/concerns/with_sidebar.rb
module WithSidebar
extend ActiveModel::Concern
included do
before_action :set_sidebar_resources

private

def set_sidebar_resources
@sidebar_archives = Archive.all
@sidebar_categories = Category.all
end
end
end


Related Topics



Leave a reply



Submit