I'm practicing my Rails development skills by building an app that will have different types of exercises for users. Most probably things like multiple choice questions for different subject matters.
One way to check to see if the questions are answered correctly is to use validations on the model. However, I don't really need to save the results, and it might end up in me creating a lot of different models, as each question will have its own validation to check each answer.
Is an alternative to create a new Controller action for each subject area? Is
How else might I organize this?
http://www.enode.com/x/markup/tutorial/mvc.html
With the MVC pattern, Controllers are usually in control of manipulating data kept by Models.
It's good form to keep most of your logic in your Controller. I'm not sure what you mean about a new Controller action, but what you'll probably want to do is set up some sort of form in your View, (see form_for) and fire that off to the Controller. The Controller does validations or whatever you need it to do.
This should be helpful:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
So for example, you might have a form in your View (a quiz for example), calculate a user's score in the Controller, and save that as a field for a user in your database.
The debate on where to put logic is as old as the involved patterns themselves. For MVC, I decided to ask myself:
Is the logic involved essential for the model?
Would the model (in itself) function well without the logic?
Is the model free of any requirements towards the controller?
If I'd re-use the model, would I want to take the involved business logic along or would it be in the way?
My general advice: Put business logic as "low" (bottom: db, then model, then controller, then view) as possible without violating any of the following constraints:
Authentication and authorization does not belong to view. It's either a property of the controller (handle things like sessions and general api access rules, etc) or of the model (authorization: who may access which content?)
UI/display/input-method related things do not get into model or db. Don't let your model/db decide if and how to render html, xml or json.
Data consistency and integrity not in controller/view. Ideally, your data model only accepts valid data, uses transaction safety and reports back failure or success to the controller. Ideally, consistency is handled at db level.
A model shall be reusable with other controller/views in new project (think of switching to another web api). Too heavy constraints may render it unusable in new situations.
there might be more...
And generally: If in doubt, put in into the controller. ;)
Related
I'm struggling to find/understand the Rails concept for handling table permissions and permissions for composite views (and composite updates).
Logically, Create, Read, Update and Destroy permissions for tables should be at table (model) level. If I know exactly which permissions a user has on a table, then it is possible to derive from that whether the user has the necessary permissions for any particular view (which just consists of data from one or more tables), and I should never have to repeat these permissions.
The 'Rails Way' would therefore seem to demand a controller for every table (model) that will be used by the application, in order to set permissions for that table in a precise way (using before_action or whatever to validate the user for the particular CRUD action). (Aside: I'm not even sure if there's a good reason for not moving the permissions logic into the model itself, which is actually what I did initially before trying to adhere to convention a little more.)
However, Rails (and possibly MVC in general?) seems to dictate that there should only be one action/view per request. So if I want to make a view consisting of three 'index' views, one for each of the models A, B and C, I need another action/view and a new validation rule for this action. This new validation rule, of course, shouldn't be necessary; the user is allowed to see this new composite view if they're allowed to see each of the individual 'index' views (or more precisely, the data underlying these views).
Also, any Create/Update/Destroy params received relating to a specific model should ideally be passed to that model's controllers for validation/execution (and there may be parameters for instances of multiple different models). I don't think this is typically how it is done, however, because it would require multiple actions being called.
Have I misunderstood the Rails methodology for handling this, or is it really expected that you effectively repeat yourself with regards to Create, Read, Update and Destroy permissions for composite views (and composite updates)?
First off the Rails framework does not ship with any provisions for authentication (well except has_secure_password) or authorization (permissions) and is totally unopinionated on the matter.
There is no "Rails way" to handle authentication or authorization.
What Rails is geared towards is the Rails flavor of REST which is focused on exposing resources through a structured API. Each controller handles a specific resource or just a specific representation of a resource.
Note that a resource is not equal to a table. Tables are an implementation detail while resources are the abstractions that your application provides as a public API.
Of course since the framework is not opinionated towards any form of authorization you can roll your own in any fashion you want such as RBAC, ABAC etc.
Of course there are several community gems such Pundit and CanCanCan that remove the need to reinvent the wheel.
(Aside: I'm not even sure if there's a good reason for not moving the
permissions logic into the model itself, which is actually what I did
initially before trying to adhere to convention a little more.)
There is a very simple reason why this is a bad idea. Models are not request aware and do not have the proper context for authorization.
A much better alternative is to use a component like Pundit that compliments the traditional MVC structure, but is its own separate entity - you could even call it MVCP.
Can anybody tell me the difference between controllers and actions in ruby on rails?
I fetched this definition from the official rails guide:
A controller's purpose is to receive specific requests for the application. Routing decides
which controller receives which requests. Often, there is more than one route to each
controller, and different routes can be served by different actions. Each action's purpose is
to collect information to provide it to a view.
I am confused.
Please, make it as simple as possible since I am newbie!
Thanks!
Controllers are just Ruby Class files which have a series of instance methods inside
Basic Explanation
Rails controllers are basically files where actions (methods) are kept
Each time you access a Rails app, you're sending a request to the system. The various technologies inside Rails route that request to a certain action, where your code can use the passed data to perform some sort of action (hence the name). The actions are kept inside controllers to give the application structure
So if you access http://yourapp.com/users/new, it tells Rails to load the new method in the users controller. You can have as many actions in the controllers as you want, but you have to tell the Rails routes system they are there, otherwise they won't be accessible
Proper Explanation
Rails Controllers are just Ruby Classes, storing a series of actions
The "actions" (instance methods) work on passed data (params) to create objects that can either be passed to the model, or used inside other methods
Whenever you send a request to Rails (access a URL), it first uses the ActionDispatch middleware to send your request to the correct Class (controller) instance method (action), and then your code does something with that data
Your job as a dev is to connect the right controllers with the right models, presenting the right data the user at the right time
DISCLAIMER: I don't write code in Rails (never did). I write Sinatra modular applications and use the MVC model.
You first need to clarify the MVC model. The MVC is an approach to programming web applications (in RoR) or user interfaces in general. So MVC stands for Model-View-Controller. I will try to explain a bit, but in order to understand this, you need to practice and play with it.
The Model: If you remove the layers of abstraction, it's your database scheme. The way your application interconnects in order to retrieve information.
The View: The way these informations are retrieved elaborated and served. Essentially is what you, or the client, see in the browser.
The Controller: The controller is what interacts with the program to produce a requested view or to alter a model. You request a view when you access a chart with statistical information, and you alter the model when you input DATA on it. In Rails ecosystem, ActionController is a class with a set of predefined methods to help you perform easier and quicker standard Controller actions like update a form, etc.
So the Action Controller allows you to alter data to your models (the db), or request a route to view your data, etc.
Action is not separated from controllers, it's basically what controllers do :-). Everything else is static.
If you feel that these concepts are still hard to grasp, try building a very basic modular application in Sinatra, and you will have a ground level view of how things work.
Explanation by Analogy (simple explanation without getting too technical)
I work in a busy office. I bark out orders (i.e. 'requests') to my staff to get em to do stuff.
e.g.
Sometimes I want a document so I can read it.
“Ngozi, pass me the ABC.ASX EOFY results please?”
Yes sir!
Sometimes I ask my staff to edit an existing document:
“Sunita, can you edit that report on the state of the union address?”
“Sure!” is the response.
I organise my staff based on the type of work they do
But I have a little problem.....I have 10,000s of different types of documents. Sometimes I want to get: (I) sports results and other times I want: (ii) the evening news, while still at other times I want: (iii) a collection of Donald Trump's latest 4 am Tweets.
So I created a new system. I have a staff member directly responsible for each type of thing.
Ngozi handles ASX (Australian Stock Exchange) Financial Results. And when I want Ngozi to do something (i.e. perform some type of action) then I tell him what to do.
Sunita works mainly on politics. Sometimes I”ll ask her to something (e.g. write up a report – this is one type of 'action', or I'll ask her to bring me a certain document – another type of action - and she'll do it. I like to get Sunita to work on politics and Ngozi to work on financial results. It's best to keep their responsibilities separated.).
And Freddie works on anything pertaining to Queen.
Etc. etc.
The meaning of the analogy?
In this case, the controller would be the person – who's responsible for handling certain types of requests. And the “action” would be the particular specific thing that I want done:
e.g.
getting a document or
edit something or even
creating a new document.
Hope that clears things up.
This may be a really stupid question, but I do not have it clear in my mind as to how it is best to manage this so want to put it down here and see what is common practice.
Coming from .net my web applications are never 1 project which is everything, I tend to at least have a data layer project which deals with persisting entities to the database and making these models represent said entity in a DB friendly manner. Then I have my UI project which has its own models which are a representation of the entity for the UI, which may have validation based information and will most likely be a more cut down model only exposing what is needed.
So the main point I am trying to get out here is that although we may have a User entity, the models to represent that may be slightly different in the UI and Data layers...
Now fast forwarding to rails, you create your project and it comes with database connectivity (which I believe can be swapped out to any flavour you want), and validation and a whole manner of other frameworks and functionality. This then seems to imply that I no longer need 2 projects, just 1 as its all included within here and all done for me, so all I need to worry about are making my models.
This is the part where I am a little confused, as lets say I am using ActiveRecord I will need to make my model and inherit from ActiveRecord::Base, then I will need to setup how this model connects to other models etc, so I have my model's data concerns sorted, now I need to setup my UI concerns, about validation and string lengths etc... now where do these go... I am assuming on the same model, but then a model isnt just a simple representation of data, its a blob of stuff containing concerns for databases and views and who knows what else.
It just seems a little odd to put everything within this one place. I know in .net there are plenty of examples where with large object graph representations in the DB the data models are VERY different to UI models, so is it wise to couple them into one model this way, or is Ruby and its frameworks so flexible in this area that you do not have these same problems? If so is there some example or article which can solidify in my mind how you sidestep the normal problems that cause you to separate your concerns to have maintainable code...
=== Edit ===
Just to try and clear up any confusion, in my post when I say my view models and view concerns, I do not mean presentation concerns. I am sorry if it came across that way. What I mean is that I may have (in a normal .net example) a UserStorage model, which has concerns about persisting a User entity. I then in the ui layer have a view which displays many users and one that displays single users in more detail. You may have 2 differing models here a UserSummary model and a UserDetails model, both partially represent a User entity, but are customised for the actual view in question, as you may get to a situation where UserDetails also becomes a composition of a User and a Company entity, which would mean there are 2 storage based classes feeding into 1 view based class.
Within the examples and guides it makes out like you should have 1 view model which deals with these concerns, as well as storage concerns, and in this case it just seems like if I were in the situation where I had a view model that was a composition of a User and Company it would seem odd for this view layer class to worry about its storage, as its never stored as itself, it is stored as 2 separate models in the database/datastore.
This is the REAL problem I am trying to get at here, it seems to be tightly coupling your view to your storage concerns which I am used to being 2 different things which should never be mixed... like putting your main course and pudding on the same plate...
In vanilla Rails, there is no such thing as a "view model".
The models handle all business logic, including query and persistence, association, and validation. You seem to be dismissing validation as a concern of the view, but this is actually a core concern for the integrity of your models: it does belong there.
That's not to say that validation shouldn't happen in the view (client-side) too, but the model has your core business rules and is the place where the validation rules are ultimately checked.
You will want your models to hold most of the logic of your application. This means things like checking if a user is valid or active, finding related records, etc. Pretty much anything that isn't presentational belongs in the model.
In the view, Rails provides helper methods for formatting. These come from modules that are included in the view instance. Helper methods have access to the instance variables of the view (your models) and are used to present them.
In some situations, passing naked models into the view makes it hard to keep things modular and organized. Some people prefer using Presenters to wrap the models before passing them to the view. It can help to organize your code, but it's also an extra layer. Presenters are not standard in Rails, but it's trivial to add this pattern using plain ruby objects or a library like draper if it makes sense for your application.
EDIT: Oh look, a most excellent blog post on just this very topic came up today, from the most excellent Thoughtbot.
In a nutshell:
if it's about the data (storage, integrity, etc.) it goes in the model
if it's about processing/calculating the data (e.g. finding all pending orders) it goes in the model
if it's about presenting the data (pending orders should have a red cancel button) it goes in the view
Since you seem to be an experienced developer, you'd probably benefit from this book http://www.manning.com/katz/ Its geared towards developers that are new to Rails (but not to web programming).
Alternatively, there is a free online tutorial also http://ruby.railstutorial.org/
And of course, the Rails guides are always a good source of information: http://guides.rubyonrails.org/
Not one mention of MVC in your question, you should look into the Model View Controller pattern.
You should also look into how migrations work.
I need to have two separate pages on the site I'm planning to build that are very similar that I don't need to introduce new DB tables or models. I would also like to stay RESTful.
If I'm to use the same controller/model I will need to have new methods other than standard index, new, edit...etc which makes it non-restful or I will have to have a variable on page that identifies it and then inside each method I will render different view accordingly.
Another idea I got was to have separate controller and model but use the same DB tables and enforce the model to use the table although it doesn't match the convention.
I'm guessing there might be cleaner way to do this. Do you know any? if not which way do you suggest?
Thanks,
Tam
I'm not afraid of the restafarian police! Sometimes your controllers need more than the 7 actions (where's the get to confirm a delete, eh?), sometimes they will need less. That's just the way it is when you start to create real world software.
If the actions you're adding are not coherent with the actions that exist (for example off by just a little bit but still off in most actions), then we're talking about a new controller IMO - otherwise adding a few actions where you need to is ok in my book.
I have an application, built using MVC, that produces a view which delivers summary information across a number of models. Further to that, some calculations are performed across the different sets of data.
There's no clear single model (that maps to a table at least) that seems to make sense as the starting point for this, so the various summaries are pulled from the contributing models in the controller, passed into the view and the calculations are performed there.
But that seems, well, dirty. But controllers are supposed to be lightweight, aren't they? And business logic shouldn't be in views, as I have it as present.
So where should this information be assembled? A new model, that doesn't map to a table? A library function/module? Or something else?
(Although I see this as mostly of an architectural/pattern question, I'm working in Rails, FWIW.)
Edit: Good answers all round, and a lot of consensus, which is reassuring. I "accepted" the answer I did to keep the link to Railscasts at the top. I'm behind in my Railscast viewing - something I shall make strenuous attempts to rectify!
As Brian said, you can create another model that marshals out the work that needs doing. There is a great Railscast on how to do this type of thing.
HTH
Controllers don't have to map to specific models or views. Your model doesn't have to map one-to-one to a database table. That's sort of the idea of the framework. Separation of concerns that can all be tested in isolation.
Why not create a model that doesn't inherit ActiveRecord::Base and execute the logic there (think the Cart class in Agile...With Rails).
Controllers don't have to be that lightweight.
However if you have some calculations that only rely on the model/s then you probably just need some sort of model wrapper for the models to perform the calculation. You can then place that into the API for the view so the view gets the end result.
You don't want the logic to be in the view. However you are free to create a database view. Except, rather than create it on the database side, create it as a new model. This will enable you to perform your calculations and your actual logic there, in one place. The pain of trying to keep your views in sync vs. the one time "pain" of creating the new model... I vote for a new model.