I've read about HMVC (Hierarchic Model View Controller) and it's flexible structure.
Have a look at this picture:
http://techportal.inviqa.com/wp-content/uploads/2010/02/MVC-HMVC.png
I wonder if the Rails 3 plugins are the answer to HMVC in Rails 3?
Based on the comments to Toby's answer it seems that you would like to be able to have MVC apps used as a component within a new app. Rails Engines (See http://rails-engines.org) provides this functionality. You simply install the engines gem and place apps in vendor/plugins and its modles/views/controller are all accessible.
This does not really conform to HMVC where the controllers in the new app delegate to other controllers. But like Toby I do not see the advantage of that.
What is nice about the Engines approach is that you can over ride any of models in the plugin by just adding a version of the model to the new apps app/model folder (same applies for views and controllers)
I have overidden app/views/layouts to give my Authentication app/plugin the same look and feel as the application it is included in.
For Rails 3 Railtie takes the place of engines and is officially supported (and actually used - Action Mailer is a Railtie plugin. I have not used it myself yet though.
Check it out at http://edgeapi.rubyonrails.org/classes/Rails/Railtie.html
A nice write up on it is also here http://www.igvita.com/2010/08/04/rails-3-internals-railtie-creating-plugins/
Rails has had plugins for a long time.
I doubt there is a technical reason why a controller couldn't dispatch to another controller, passing the request object along a chain. I just don't know what you gain by doing so - the diagram looks like spaghetti.
To me it's a misuse of MVC. I would suggest it is much simpler and more maintainable to push logic into lower-level models and classes and create a single controller that fronts the this logic, rather than creating a chain of controllers.
In the Rails 3 blog post, DHH mentioned the Cells project. I haven't used it but I am going to check it out.
The cart example shows well how that kind of functionality might clean up your application code. Code which retrieves data should be placed somewhere in controller. In every action or in a before filter. The Cell seems to be much better solution.
Please look at this rubyonrails-talk post: https://groups.google.com/forum/#!topic/rubyonrails-talk/0c4TT7UOGCw
Related
I'm rewriting one old app - Rails 1.2.6 :)) - completely in Rails 4... so you can imagine the information overload.
It's going quite well so far but I'm currently struggling with one task that should be pretty obvious but it lacks proper documentation and there are just too many blogs with different solutions to this issue.
I have a custom class with custom text conversion functionality (using Redcloth, autolinker, Sanitize etc.), let's call it Textilize class. It's used in models as well as controllers so I guess the best solution would be to create a gem from it. I want to attack gem creation later though since it's just a simple one-file class.
So for now I just added textilize.rb file to /lib directory and added config.autoload_paths += %W(#{config.root}/lib).
It works fine and I can now use it in the app without requiring it in the models and controllers.
Is this a good practice in Rails 4? Is it thread-safe?
If not, is there a way to refactor it without creating a complete gem for now?
Thanks!
"Is this a good practice?" I think it is.
"Is it thread-safe?" I don't know
Any other way? I will use your solution if the lib is crossing Model and Controller and it is simple. If it get rather complex, I will create a plugin. If it is complex and can be extended to be useful on other apps, I will create a gem.
Hey guys and merry christmas!
I'm new to ruby on rails and I'm still a little bit confused about some stuff:
When do I need to create a new controller and when not?
I want to create an app with a single searchbox and search through all of the articles. Should I create an Controller for the startpage (the searchbox) and for the search? Should I create controllers for the static pages?
Should I use an Admin interface gem or create my own?
The normal user should now have access to creating articles, just the admin. Should I use one of the admin interface gems or create my own?
Ruby on Rails follows the MVC framework, controllers are classes that contain your actions, so you need to add an action for every function your website will provide.
Technically you could have all actions in one controller but that would be just terrible, so we usually create different controllers to organize your routes and code in a better way.
Follow the Rails guide on controllers.
For the admin interface gem, you could use devise and cancan, they are both very reliable and well tested.
Ruby on Rails is indeed MVC, which means that controllers connect Models to Views. So in general it is good practice to think more resource-oriented: per resource you want found/presented, you create a controller. In your case something like:
ArticlesController : your main view, with the searchbox
PagesController : for static pages, if you need some erb/haml
admin/ArticlesController: for administration of the articles
Now, completely static pages can just as well be placed under the public folder, no need for a controller unless you need some dynamic info to be on the pages (e.g. a total count of articles).
With regards to your search-box: imho this is just a parameter for your index page. E.g. on the index you show the ten most recent articles, and when searching on some term, you show the relevant articles, but on the same controller and the same action.
With regards to the admin interface: yes, use gems like rails_admin or active_admin and it will get you started in no time at all. So definitely do that. But those gems are, of course, very general and might not suit your needs completely. It that should be the case, you can always easily revert later.
HTH.
Merry christmas!
As Khaled suggested Rails being MVC architecture it is always good to have controllers of each page. Even though you might have a static pages for now, but latter when you are trying to make the site dynamic one, then you will be in whole lot confusion of where to add a method for a particular view page.
Generally it is better to use a gem instead of making it from scratch.
You can look into this link which teaches you how to use devise and cancan with twitter bootstrap(for views). But if you are planning to learn rails then I better recommend you to do it from scratch as you will have an idea of what is happening. You can see this tutorial which does most of the task through scratch.
Enjoy Rails!!
I've finally started making a Rails app from scratch and I'm getting the hang of it, but the only problem is that making all the models/controllers is getting really repetitive and totally throwing the whole DRY concept out of the window as I'm basically copying controllers and renaming them/adding/disabling fields. I have:
Projects
People
Tasks
Messages
etc and the first three need to pretty much have the same layout and CRUD. Is the only way of not having to manually create all of the actions/views each time scaffolding? If so, what other things does scaffolding generate that I need to be aware of. I've been cautious of using it in the past because I wanted to know how my application worked in the tutorials.
In my opinion scaffolding is not for new rails programmers, it should only be used after you figured out rails yourself and with a criticizing approach. It may generate whole files that you have no need, define unneeded routes etc...
You can have a look at the full details of what scaffold creates here
As for the repetitive controllers you are making I could suggest using the gem InheritedResources which eliminates a lot of this duplication (at least while you are at the basic CRUD controller operations)
InheritedResources sets the basic controller index/show/destroy/create/edit actions for you, all you have to do is to inherit from it using:
class ProjectsController < InheritedResources::Base
end
In case you have to, you can override actions by defining them yourself.
It's an excellent point. You generally want to keep your controllers as thin as possible, and certainly thinner than what the scaffolding gives you.
The way I like to think of the scaffolding is that it's good to use for your first feature in a new Rails app as an example of the current best practices and things you might want to know about. After that, however, write your controllers yourself, and factor out any duplication.
For additional ideas, you might want to read/watch...
Objects on Rails
Hexagonal Rails
Architecture the Lost Years
I'm new to Rails, and have been learning with Rails 3 on a side project. There are times when I want to write some code that does not belong in my models or in my controllers - concerns that are related to a model and/or controller, but i don't want to clutter up either of them with the implementation details of what i am writing.
For example: a project i'm building uses Janrain's authorization system (RPX) so i can get oauth, openid, google, etc. authorization. there's a nice chunk of API code that they provide so i don't have to write it all myself. this code doesn't belong in the login controller or in the user module. it's authorization code, so it needs to be accessible by the login controller, but it's not part of that controller.
Where do you put this code? it's not model code. it doesn't belong in the controller.
... thanks in advance.
You should be able to use lib folder in your root directory (unless it's changed in Rails 3).
You can refer classes from there without require statement.
A 'common' suggestion is to say 'put this stuff in lib'. But there are other places to consider:
Consider making a subfolder in app. Some examples include: app/workers, app/observers, app/sweepers, or whatever makes sense for you.
Consider using config/initializers for initialization code.
Lastly, and only if the above don't make sense, you can use lib. Don't forget you can use subfolders to keep it from getting too junked up.
And, once you get things working and polished, consider extracting your code into gem. See, for example, the RailsCast on Creating a New Gem with Bundler.
I have a Rails application with several models-views-controllers which have some similar characteristics, for example 5 different models can be commented on, voted on or tagged, I am also heavily using external plugins.
At the moment I introduced comments, votes, tags, etc. only to a single model (and its view and controller). However, now that I am happy with the results, I want to cut out this common functionality from the particular MVC of one model and allow access to it from all other models.
Some questions before I start doing this (and maybe some general advice will also be great):
1 - How should I go about it? I was thinking creating a module in "lib" directory (is it the same as mixin class?) and then moving reusable view code to common partials. What about the controller code?
2 - As I was just learning Ruby on Rails during the coding of the first model, I went with a probably incorrect way of adding a bunch of methods to the controller. I have a method that adds a comment (addcomment), adds a vote (addvote), etc. All these methods require non-standard (non-RESTful) routing via :collection. From what I understand, the correct way would be to move comments controller functionality to its own controller and access via standard RESTful routes. Is this what I should be doing?
3 - Many plugins (eg. act_as_commentable) do not explicitly require loading a Module, just a line "act_as_commentable" somewhere in the Model. Can I use something like this for my common functionality? How does it work?
A simple way is to split the code into modules and use mixin.
A better way is to write your own plugins for your common code.. like act_as_commentable
you can learn about it here: http://guides.rubyonrails.org/plugins.html
The correct way is to do a comments controller, and have it nested to your models, giving a restful routes like this: /mymodelname/1/comments.
An easy way to make such controllers is by using inherited_resources plugin.
scroll down to the "Polymorphic belongs to" section- there is a comments controller example
For repeated model code, put it in a module in the lib directory.
For controller code, put your duplicate code in ApplicationController.
For your view code, use partials.