General Questions about Ruby on Rails - ruby-on-rails

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!!

Related

Rails application with multiple roles

I have a rails application with 2 roles, say admin and user. But the thing is, The admin doesn't use a backend like ActiveAdmin for example. I want both Admin and User to see the same views, but depending on the role, I restrict what they can see. I'm using Cancan, but since for example both admin and user can see the product page, I end up with many conditions inside the view and controller actions stating for example if this is an admin show that, if not then show that instead.
So I don't really think that this is the "Rails way". I end up with many repeated code, and code inside the views which doesn't really support the idea of keeping the logic away from the views.
So my question is, What's the best way to implement such a scenario with many roles but the same views.
Thank you.
I'm thinking of two options currently, but I don't like either. One is to redirect the admin to another view, but this way most of the view is the same hence it's not DRY at all.
Option 2 is to use the exact same view, but add many conditions in the view, so I end up with a huge complex view with code. I'm trying to find a way that keeps things DRY yet simple, and keeps the views code free.
You can have the admin module under seperate namespace and users as the default namespace. You can extract the common code under partials and use the same in both admin and user module.
This way you can separate the code for user and admin, and if sometime in future if you decide to go for a different views for admin and user. It won;t be much of a task.
Have controllers as
app/controllers/admin/articles ------ for admin users
app/controllers/articles ---- for normal users
and
views
app/views/admin/articles
app/views/articles
app/views/shared
There are different possible approaches. A variation of the 'decorator' pattern would come to mind as described here
It's some time I last read it, but I think the basic idea is to put the logic in the model or helpers. As soon as a user logs in and you can see if he is an admin or normal user you have methods that return the necessary html or text.
A more simple approach would be to just have two partials for everything. Either as Ross says in a separate admin namespace or even simpler (but more work if you later need to change that) just like _user_view_something.html.erb and _admin_view_something.html.erb.
Somewhat similar thoughts go into the DCI pattern. This Blog gives some nice overview how this could play into Rails. The article is more about permissions, but again the basic idea is to supplement the user object with the necessary functions.
So you have the basic "do_something" method which renders something or places some information in the view and replace it with the one that fits to the role the actual user has.

Ruby on Rails simple website layout

I'm learning RoR, I've read some tutorials (railstutorial for the first one),
but I've a problem to define the logic layout of the my first simple website.
The structure is:
When you go to mysite.com you see a welcome page with the signup form or the link for login.
If you signup or you login into the site, you are at mysite.com/dashboard and you see a list of your messages.
You can go to mysite.com/$username and you see a page with a form where you can write a message for the $username.
Stop. That's it. It's very simple, I know, but is for learning.
The problem is this: I'm new to MVC paradigm and I don't know how structure the logic layout of my app. Of course there'll two models: User and Message. But for controllers? And which functions in any controllers? Should I use scaffolding?
Please give me a help, I'm very confused.
Thank you.
Controllers are the logic for the data, so to login/sign-up is really validating/creating a user, if you need to view the users dash board, well that's a look up on the user data so he goes there as well.
The messages, that will be a separate controller that can create/view messages!
As others have pointed out, your controllers contain the logic for your code and invoke views based on that logic by rendering or redirecting to pages. You can define whatever actions you want in your controllers, and then use routes to map a particular URL to a controller action. That being said, Rails gets a lot easier if you "go with the flow" and make some simple assumptions about the actions that could happen. Both your users and your messages represent rows in their respective database tables. There's no much you can do to a row in a database table - you can Create it, Read it, Update it, or Delete it (CRUD). If you define your actions in terms of these four logical actions, Rails lets you generate some easy routes.
You can back into any URL schema that you want, but what you are describing is:
Read the messages that are for a user on the dashboard
Create a message for a user when you go to another page (mysite/username)
Each of these maps to a CRUD action that you should be defining in your controllers.
Agreed also with other advice to simply do a few more tutorials that will probably clear this up.
If you haven't already, read Getting Started with Rails. Look out for the discussion on MVC and scaffolding. Playing around with scaffolding can help you learn where things go and is a great place to start for beginners.
Also, I highly recommend this book: Agile Web Development with Rails. It is very hands on and an easy read.

Rails: Where do you put non-model code?

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.

Hierarchic MVC in Rails 3?

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

Correct way to optimize repeated Rails code

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.

Resources