Nested resources
[size = medium] [/ size]
When the application of nested resources, REST development will become more interesting. In this chapter, you will be more simple to understand the importance of URL of the URL, but also the concept of REST has more clearly understood.
Nested resources, that is what the Father - son relationship resources. Rails at Medium, which is a model of relations: 1 to many relationship. In our example OnTrack project, just like the relationship between projects and the same iterations. Nested REST controller is still responsible for handling the operation of a particular resource, but a "son of" controller is concerned, it must be "the father of" information resources.
It sounds very complicated, but reading this chapter, you will soon be fully understand.
Rails in accordance with the REST approach, Rails resources such master - from relationships reflected in the URL, the URL and maintaining the essential characteristics of this compact. OnTrack in this case, we will, through the two resource project and iteration to describe this.
First, we create iteration of the resources and the creation of iterations of the table.
> ruby script/generate scaffold_resource iteration name:string \ start:date end:date project_id:integer > rake db:migrate
Projects and Iterations are "1-to-many" relationship, so we have to make some corrections model:
Listing 1.4: ontrack / app / models / project.rb
class Project < ActiveRecord::Base has_many :iterations end
Listing 1.5: ontrack / app / models / iteration.rb
class Iteration < ActiveRecord::Base belongs_to :project end
Apart from the creation of a model, controller and view, generator simultaneously at config / routes.rb, the creation of a definition of routing items:
map.resources :iterations
The routing and resource project is very similar to, but we do not forget the relationship between iteration and project. But it is clear that this route did not take into consideration of this point. For example, new_iteration_path Ways to generate a URL "/ iterations / new", and does not contain such an important information: This iteration should belong to which project? Therefore, we should be aware that, in the absence of a "parent" resource, then a "child" resources are not in any sense!
Rails will be such a master - the relationship between the reflected from the URL, the therefore, we need to modify the default look of the generated routing:
map.resources :projects do |projects| projects.resources :iterations end
Routing of this now as a nesting resources, and you want to operate this iteration resources, resources must be based on the above project. Corresponding to the URL should be like this are the following:
/project/:project_id/iterations /project/:project_id/iterations/:id
For example, if I enter the URL
http://localhost:3000/projects/1/iterations
IterationController will call the index method, in this way, the can also be submitted by the parameters: project_id to get resources project. It is worth noting, URL link of the characteristics of a resource, in fact, is equivalent to the following relations:
/projects/1/iterations <=> Project.find(1).iterations
Nested URL is still the simple URL - URL is still only show that the resources, but not action. Simply put, the use of resources if a two REST-style URL pose, it is a nested resource. The following URL to call the show action will give us a clear understanding of this point:
http://localhost:3000/projects/1/iterations/1
Nested resources in the controller code
IterationController new generation does not know it now has to deal with nested resources - This means that each method, at least should be, "Father" resource project. Therefore, the index method is still displayed all of the iterations, although the URL has made it clear that should be shown in a project are all under the iterations:
Listing 1.6: ontrack / app / controllers / iterations controller.rb
def index
@iterations = Iteration.find(:all)
respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @iterations.to_xml }
end
end We must re-index Writing Ways to ensure that we were only one project under the iterations.
Listing 1.7: ontrack / app / controllers / iterations controller.rb
def index
project = Project.find (params [: project_id])
@ iterations = project.iterations.find (: all)
...
end
We must let the controller in all the way to be able to at job / projects /: project_id for the prefix on the URL. This means that we must not only index Ways modify, create, update and so on Ways must also be modified. The following sections we will progressively introduce.
In the "path" and "url" helper methods use parameters
At config / routes.rb in additional resources, not just added a new definition of routing, but also automatically adds a new helper method. As the definition of the routing, the new helper methods need a project-id as a parameter. For example, through "iterations_path" this helper method to get a project under all iterations. Helper method's name is not named nested manner, the different transmission parameters is not the same. For nested resources, the "child" resources helper method parameters, which are "parent" resource resource id, in this example is a project of the id.
The following as an example, we have to create a link, this link can display a project under all iterations.
link_to "Iterations", iterations_path(project) => Iterations
Iterations_path one of the parameters of "project" is the object of a resource. In order to better understand the role of this method, we put it on a page to see: Listing 1.8: ontrack / app / views
/projects/index.rhtml ... <% for project in @projects %> <%=h project.name %> <%=h project.desc %> <%= link_to "Iterations", iterations_path(project) %> <%= link_to "Show", project_path(project) %> <%= link_to "Edit", edit_project_path(project) %> <%= link_to "Destroy", project_path(project), :confirm => "Are you sure?", :method => :delete %> <% end %>
...
Well, if we pass the wrong parameters iterations_path give what will happen? That will lead to all of the features are effective, and the page will also display abnormal. For example, the reality of all the iterations the following pages:
Listing 1.9: ontrack / app / views / iterations / index.rhtml
...
<% for iteration in @iterations %> <%=h iteration.name %> <%=h iteration.start %> <%=h iteration.end %> <%= link_to "Show", iteration_path(iteration) %> <%= link_to "Edit", edit_iteration_path(iteration) %> <%= link_to "Destroy", iteration_path(iteration), :confirm => "Are you sure?", :method => :delete %> <% end %>
...
We can see that the first iteration parameters are now the target. This leads to all the methods are a failure --- for obvious reasons, because at / config / routes.rb, we are defined by the first parameter should be a project id, rather than iteration id. If you want to display this page properly, need to be modified as follows:
Listing 1.10: ontrack / app / views / projects / index.rhtml
...
<% for iteration in @iterations %> <%=h iteration.name %> <%=h iteration.start %> <%=h iteration.end %> <%= link_to "Show", iteration_path(iteration.project, iteration) %> <%= link_to "Edit", edit_iteration_path(iteration.project, iteration) %> 20 1 RESTful Rails <%= link_to "Destroy", iteration_path(iteration.project, iteration), :confirm => "Are you sure?", :method => :delete %> <% end %> ...
Parameters in order to allow the order is correct, we can show by another means specified parameters:
iteration_path (: project_id => iteration.project,: id => iteration)
If you think the use of the object as a parameter is not clear enough, you can take a look at the way.
Add new Iteration
We remain at the current examples are added to this function. In order to achieve this function, we only need a simple tinkering ProjectController the index.rhtml:
Listing 1.11: ontrack / app / views / projects / index.rhtml
... <% for project in @projects %> <%=h project.name %> <%=h project.desc %> <%= link_to "Iterations", iterations_path(project) %> <%= link_to "Show", project_path(project) %> <%= link_to "Edit", edit_project_path(project) %> <%= link_to "Destroy", project_path(project), :confirm => "Are you sure?", :method => :delete %> <%= link_to "New Iteration", new_iteration_path(project) %> <% end %> ...
Here we used the "new_iteration_path" the helper methods, and to project the object passed as a parameter into account. This helper method will generate the following html statement:
link_to "New Iteration", new_iteration_path(project) => New iteration
If you click on this link, it will call the new method IterationController, in this method, you can get project id (in this example is the "one"). In this way, used to create a new iteration of the form can use this project id of:
Listing 1.12: ontrack/app/views/iterations/new.rhtml <% form_for(:iteration, :url => iterations_path(params[:project_id])) do |f| %> ... <% end %> =>
The "params [: project_id]" In fact, can also be omitted, Rails will automatically deal with this variable, that is to say, the above code, and the following are equivalent: form_for (: iteration,: url => iterations_path) because we have at / config / routes.rb define the routing, so that to ensure the use of post submission "/ projects/1/iterations" link, we will call the create method IterationController.
Next, we wish to change the look IterationController's create method to ensure that we have created is based on the iteration of a project above:
Listing 1.13: ontrack / app / controllers / iterations controller.rb
1 def create
2 @iteration = Iteration.new(params[:iteration])
3 @iteration.project = Project.find(params[:project_id])
4
5 respond_to do |format|
6 if @iteration.save
7 flash[:notice] = "Iteration was successfully created."
8 format.html { redirect_to iteration_url(@iteration.project,
9 @iteration) }
10 format.xml { head :created, :location =>
11 iteration_url(@iteration.project, @iteration) }
12 else
13 format.html { render :action => "new" }
14 format.xml { render :xml => @iteration.errors.to_xml }
15 end
16 end
17 end At the first "3" line, we use "project_id" This parameter, in section "8" line and "11" line, we use the "url" helper method.
We also need to be amended following a number of shows that iteration Edit link - because we need to put together iteration and project relevance.
Listing 1.14: ontrack / app / views / iterations / show.rhtml
... <%= link_to "Edit", edit_iteration_path(@iteration.project, @iteration) %> <%= link_to "Back", iterations_path(@iteration.project) %>
Edit Iteration
In order to be able to edit the iteration, at least two places need to be amended. 1> in the view form_for method parameters, the current iteration, only one parameter, but also the need to increase projectid.
form_for(:iteration,
:url => iteration_path(@iteration),
:html => { :method => :put }) do |f|
Need to be amended as follows:
form_for(:iteration,
:url => iteration_path(params[:project_id], @iteration),
:html => { :method => :put }) do |f| We also need to amend the update method, the purpose of amending the same.
Listing 1.15: ontrack / app / controllers / iterations controller.rb
1 def update
2 @iteration = Iteration.find(params[:id])
3
4 respond_to do |format|
5 if @iteration.update_attributes(params[:iteration])
6 flash[:notice] = "Iteration was successfully updated."
7 format.html { redirect_to iteration_url(@iteration) }
8 format.xml { head :ok }
9 else
10 format.html { render :action => "edit" }
11 format.xml { render :xml => @iteration.errors.to_xml }
12 end
13 end
14 end No. "7" line need to be amended as follows:
format.html { redirect_to iteration_url(@iteration.project,@iteration) } So far, the new operation of the majority of resources Iteration can be a normal job, but there are still some details we do not deal with the place. Next time will talk about how to customize the Action.
- Transfer from women and men ( )







