The common situation when developing a website is to have one index action that lists and creates multiple different resources.
For example, lets say that you have transactions controller that lists both payments and expenses on same page (where expense is an auto-calculated group of payments).
On transactions index action, there are two forms: one for creating new expense, and the other for creating new payment. Both of these forms point to submits to their respective controllers create action. If the data is invalid, it should redirect back to transactions#index and display error messages.
This is just a general discussion, it is not related to specific problem, so lets assumpt the following:
No AJAX will be used
We cannot generalize expenses and payments into shared base
The problem is that while we can submit data to different controller, we can't get response from it. We can redirect back, but then we'll loose our data and validation errors. There are some 'hackish' solutions to this, but I would like to keep this simple.
One way of solving this would be to implement specific actions on transactions controller (like create_expense and create_payment). It would work, but it would cause code duplication and breaking of REST and I dont like it.
The real question is: how can we re-use controller actions from various other places in website, and make it feel like a natural process?
You could include a hidden_field :redirect_back_to => transactions_path in your forms, and then just post the forms to their respective controllers, and let the controllers redirect back to params[:redirect_back_to] if it's present.
This might seem a bit hacky, but I think it's the easiest solution if you don't want to use AJAX.
Related
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.
I have a wizard that is responsible for creating 3 different types of resources. When the user completes the wizard, the user hits submit and an ajax POST is sent to create the 3 new entries. These 3 resources all belong_to User. I was wondering if I should POST 1 ajax request to the User controller containing details of all 3 resources, or if I should POST 3 separate ajax requests to each resource's controller. What's the proper way to do this? Thanks!
Firstly, a minor correction: you cannot post a request to a resource model. I believe what you are talking about is posting to the models' respective controllers (which I presume to exist).
If you have a single form for the wizard, then as you understand it, it will post one single time. Why not work with that? But before we go with that, let's address the alternative.
What you are suggesting, starting 3 ajax requests, brings in more problems than it solves. For example, what if there is an error in one of the requests? How do you cancel the other two, if you want to follow the principle of atomicity. There may be other reasons why such a design consideration is going to be a bad one, but I think this is trouble enough. Let's move on to how we can handle this.
The controller that is responsible for the wizard's form should provide a bit more logic to handle the 3 additional resources. If the types of resources are similar, you could be using single-table-inheritance or something to simplify some of the controller code, but that's not so relevant. We will assume that the resources are not similar at all.
Simply put, you could build the form as a multi-model form. If users can create multiple entries of each type of resource then you will have a form that creates multiple child models.
If you only need one of each resource, then the answer is really simple, just use the accepts_nested_attributes_for method for each type of resource in your User model and the fields_for method in your views.
If you need multiple of each resource, then perhaps you may wish to find out more about multiple children models in a form.
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. ;)
I have a question about how to design my controllers properly.
Project is fairly simple: blog, immage gallery with categories and images inside them, news secion.
However I don't know how to organize my controllers for this because I want to make somewhat admin panel where administrators can edit, add and modify these things. I've came up with 3 scenariosu so far...
Admin panel will have links to site/controller/edit, but layout for these action results will be different from standard one.
Admin controller will have all these actions like BlogAdd, BlogEdit so that url will be something like /site/admin/blogedit.
Create copies of Blog controller in admin folder so url will be like /site/admin/blog/edit - i sense problems with routing since 2 controllers with same name does not sound like a good idea, however I like ho URL looks in this situation.
What I'm trying to make is CMS somewhat similar to wordpress, where blog creation,editing and deletion is completely separated from default blog itself.
I suggest you stop thinking about URLs and Controllers being a 1->1 relationship. This will make things MUCH easier and less confusing. You can make the URLs work however you want with MVC's routing mechanism and there's no reason to restrict your controller design/organization because of the URLs you want, because you can always adapt the routing to with with the URLs you have in mind.
While building the website, just focus on the controllers (and the general interface) and ignore the URLs until you get to that point, and then when you come up with a good URL scheme go into the routing system and add the routes to connect to your existing controller actions as you want.
Once you code out your blogging engine you will have a much better idea of the user workflow and will probably find different ways to organize your URLs, and you can then reorganize your URLs without touching the controllers themselves.
As to your first requirement:
There are two ways to do this depending on your end goal. If your goal is to display the same core content, but have different user options available (different overall layout, additional buttons on the page, etc..) then the best idea is really to just pass in an IsAdministrator property in your view model, and make the slight changes to the page based on if that's true or false. The reason is because you still (most likely) want the core of the page to be the same, and this keeps you from duplicating code that is related to the core data (data that's being displayed for both admins and non-admins).
Edit: So in summary, organize your controllers based on what makes it easier to develop with, not based on how the user interacts with the system with. You can always change the latter, changing the former is harder and will make maintenance annoying.
You can create Areas in your MVC project and have your admin functionality in a controller in your admin area.
This will allow you to easily seperate your administration functionality from your general blog functionality.
That's how I'd do it.
Why don't you keep the routes the same and handle the different roles via security? For example:
/blog/name-of-topic/view to view a topic (all users)
/blog/name-of-topic/edit to edit a topic (only enabled for logged in users)
/blog/add to create new topics (only enabled for logged in users)
You can handle these actions in a single controller and decorate the actions that require logged users via the [Authorize] attribute. Same thing with the links on your views, you would enable the links to edit and add topics only to visible users.
You could still have a separate panel to allow admins to hit the aforementioned add/edit links .
I'm still just getting into MVC, and for my first real project I plan on creating a blog. This will be extremely basic (at least at first). Everything I need is going to be on the same page. Here are the initial features I am shooting for:
User should be able to log in, but not register (I will be the only one able to post, and I added myself directly to the DB.
Blog posts should be listed in descending order with a Title, a post date, and the body. No comments required for now.
The bottom of the page will always have an area to make a new post, assuming you're logged in.
Since I'm still new to the MVC structure, I'd like some advice on how it should be organized.
For my models, I figured I should have a post repository and a BlogPost class for the post data which can be used for both the posting and retrieving. I would also need a class for the user.
When it comes to controllers I'm a bit less confident. Should I have a different controller for every type of action? For example, posting should have a controller, retrieving should have a controller, logging in should have a controller, etc?
As for the views, since I really only need a single page, should I only have a single view and have that view output the appropriate content from my controllers?
Just let me know if I'm on the right track, I suppose. If my thought process is way off, please tell me. I've just started working my way through Steven Sanderson's MVC 2 book, but I feel like I need to go out on my own and play between my reading sessions.
Thanks.
Controllers should be grouped by functionality. You could also have a controller per resource (REST). You could have an AuthenticationController which handles authentication and PostsController which will handle the posts retrieval and adding a new post. As far as the views are concerned assuming you will have a single page that will list posts and add new posts you could have a single view but maybe with multiple partial views/editor/display templates.