multiple controllers in one view (ruby on rails MVC)
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
andupdate
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.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.
- 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 yourHomeController
has access to, ideally yourPost
model (i.e.Post.feed(current_user, location)
) or a service object. Another, hacky way to do this is by placing these methods in theApplicationController
, 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 abefore_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
Jruby: Import VS Include VS Java_Import VS Include_Class
Singleton Method VS. Class Method
Round a Ruby Float Up or Down to the Nearest 0.05
Ruby - Activerecord::Connectionnotestablished
Ruby Array of Hash. Group_By and Modify in One Line
Ruby on Rails - Differentiating Plural VS Singular Resource in a Rest API
Subtract Dates in Ruby and Get the Difference in Minutes
Passing @Object into a Rails Partial Render
Ruby: How to Store and Display a Day of the Week
Concurrent Requests with Mri Ruby
Ruby on Rails: Yielding Specific Views in a Specific Places in the Layout
How to Find a Model's Relationships
How to Use Rspec Expectations in Irb
Changing Active Model Serializers Default Adapter
Trouble Resizing the Default Image with Paperclip
Define_Method: How to Dynamically Create Methods with Arguments