I've created in rails(3) a new html page in my project model named contact.html.erb and I am interested in linking to it from a different page, i've added the code:
<%= link_to 'contact', contact_project_path(#project) %>
Project is a model that belongs_to a User (which is the contact in the contact page).
This link gives me an error message saying that contact_project_path doesnt exist. I know I need to define it somewhere but I don't know where or how. I want the page to be specific per project. I've created an action in the project_controler named contact and left it empty.
What am i missing?
I've searched for a soloution for quite some time and haven't found an answer to this question anywhere else. I'm aware its a little bit basic but I have no other options.
-REVISED ANSWER-
Based on comments I see you're not trying to associate a contact model, just a view. In that case, you still need to change the routes file, but you need to decide if you want to get a single contact page for all projects, or one contact view per project. IE:
# Collection Contact
example.com/projects/contact # IE One contact view for all projects
# Member Contact
example.com/projects/1/contact # IE One contact view per project
Either way you need to use a block for your project resource in your routes file. So, if you want there to be one contact page for the collection (all projects), do:
resources :projects do
collection do
get 'contact'
end
end
Or, if you want one contact view per member (one per project) do:
resources :projects do
member do
get 'contact'
end
end
Either way this will give you helper methods which you can put into link_to
For the collection it should be contact_projects_path (no arguments), and for members it should be contact_project_path(#project) (pass in the project as an argument.
You can use get post put delete or match as a parameter in a collection or member block, that just tells Rails what kind of request to handle at that URL, and what helpers to generate. For normal views you want a GET request.
I hope this finally answers your question :)
-ORIGINAL ANSWER-
This is for routing to a MODEL, not just a view
Add to your routes.rb:
resources :projects do
resource :contact
end
If I understand your question correctly, that should create a helper called project_contact_path().
This record will be projects/123/contact.
If you want more than one contact per project, you'll need to make it plural (resource :contacts). Then your records would look like projects/123/contacts/123.
See http://guides.rubyonrails.org/routing.html
You would link to this using link_to( project_contact_path(#project) ) if there's only one contact per project, or link_to( project_contact_path(#project,#contact) ) if there are multiple contacts per project.
Have a look here:
http://edgeguides.rubyonrails.org/routing.html
You should be aware that contact_project_path(#project) isn't a restful routes (unless contact_project is a model but there is little chance). You'll have to declare this name, use :as
Related
I am using form_for in the _form.html.erb view in order to create my form for both the edit and new actions, as per a standard scaffold.
I have a model Owner which has_many pets.
I would like to put an html link on my views/owners/show.html.erb to create a new pet for said owner. This link will point to the new action of pets_controller.rb which when accessed will render the view in pets/new.html.erb
What I want to happen is for the the owner_id to be passed with the link in the url to the new action of pets_controller.rb and then be used as the default for a collection_select in pets/new.html.erb
So I have a link to create a new pet but because that link was on a specific owner page, I want the form to create a new pet to have that owner already set, so the user does not have to select from the list.
This has to be done without changing the behaviour of the edit action/view in pets.
I know that I can pass GET arguments then access them in the controller via params, then create variables in the action which are passed to the view. I can then manually check for a default and set it in the view. I do not need assistance in coding if this is the only solution.
Is there is a better way to do this? A format with which I can pass the params such that the view will just pick them up? Without manually editing my controllers and views?
While my personal inclination would be to do as you said and pass a parameter in the link helper and then access the params array in the pets view, you may find that this is the perfect opportunity to explore Nested Resources. Essentially, you could declare owners/:owner_id/pets/:pet_id route with:
resources :owners do
resources :pets
end
You could then link to this route, and reference :owner_id without having to append the query string to the URI (making somewhat cleaner for reuse).
This is likely more work for you, but also potentially more extensible (and certainly more inline with the Rails way of doing things).
REVISION
Added the following regarding link helpers to the comments, but wanted to reflect it in the answer as well.
To show a pet should be:
<%= link_to owner_pet_path( owner_variable, pet_variable) %>
To view pets' index index should be:
<%= link_to owner_pet_path( owner_variable ) %>
The answer given to this question is fantastic.
As #ConnorCMcKee suggests it would be wise to consider nesting your routes. However, if you are a beginner as myself I found that it helped my learning to simply nest my second controller into the first (i.e. nest PetsController into OwnersController) as a first step. Then afterwards I would continue with the routes.
The method would be something like:
1./ In owners/index.html.erb:
Links to PetsController index action
The key to make this work is to send the :owner_id in your link parameters. Then that Pets index action will have access to that :owner_id and know which :owner_id called it.
2./ In PetsController you would then be able to find that Owner using that id, like so:
params[:owner_id]
Then your actions can start to take advantage of knowing what Owner called them. Remember though that all your redirects inside your PetsController need to preserve params[:owner_id]. That is because once you are inside that nested structure you have to maintain it and stay inside it and always know which :owner_id you are working with.
I want to have a link at the bottom of my show.html.erb that links to the new action in a different controller.
class Sample < ActiveRecord::Base
belongs_to :song
end
class Song < ActiveRecord::Base
has_many :samples
end
So, at the bottom of the show action for songs, I want to link to new for samples. This seems pretty easy, but I'm struggling to figure this out. I would also like to pass the id from the song to the form as :song_id
Fiddy, because you're new, let me explain how this works...
Routes
Your problem is that you don't understand the Rails routing structure - I'll hopefully explain it for you.
Rails, since it's an MVC framework, builds a series of "routes" for you. These "routes" are stored in the file available at config/routes.rb.
Routes, as described by the Rails documentation are as follows:
The Rails router recognizes URLs and dispatches them to a controller's
action. It can also generate paths and URLs, avoiding the need to
hardcode strings in your views.
The most important thing you should consider here is the way the routes generate paths for you. These paths are simply Rails "helper" methods, which you can call from your views. The reason these exist is two-fold -
They provide you with a DRY (don't repeat yourself) way of accessing / manipulating data
They are constructed around objects, helping maintain the object-orientated nature of Rails
These will likely mean nothing to you. However, what you need to realize that if set up your routes correctly, it seriously helps your app's infrastructure immensely.
--
Rails
This leads us quite nicely onto appreciating the way in which Rails works
Rails is an MVC (model view controller) framework. This might seem somewhat trivial, but in reality, it's one of the most important aspects to learn about Rails development, and here's why:
The Rails software system works by taking "requests" (user input) and then routing them to specific controller#actions. Those controllers then build model data from the database, and will translate that into either variables or objects, which you can use in your view.
The reason I mention this is that this type of development takes a lot of getting used-to, in that your program's flow is not about logic / functionality, but the accessibility of data. Therefore, when you ask about the routes or other parts of your app, you need to firstly remember what data you wish to show, and also how you want that data to be shown - this will give you the ability to construct & use the routes / controller actions which will get it to work properly
--
Fix
In terms of what you're saying, the way you'd go about achieving the result you want will be to use a nested route:
#config/routes.rb
resources :songs do
resources :samples #-> domain.com/songs/:song_id/samples/new
end
This will create a new route for you (which you can check by firing rake routes in your rails c (console). This will give you a path to use for your samples#new action:
#app/views/songs/show.html.erb
<%= link_to #song.name, new_song_sample_path(#song) %>
The above link will take you to the samples#show action, which you'll be able to populate with as much data as you require from the samples controller. The important thing to note is this action will have params[:song_id] available for you to either build an object from, or otherwise
<%= link_to "New Sample", new_sample_path(:song_id => #song_id) %>
Where #song_id is the variable that has that id in it.
Set paths in link_to tag which you can get by running rake_routes in terminal.
Ex
link_to "New song", new_sample_path(#song)
In the example given above #song is the instance variable of your current page.
You can also get some idea from here:
link_to Base URL Randomly Changed
Song Model:
accepts_nested_attributes_for :sample, allow_destroy: true
Route:
resources :songs do
resources :samples
end
Song's Show file:
<%= link_to "New Sample", new_song_sample_path(#song) %>
in url it will be:
/songs/:song_id/sample/new
Try this and let me know it works or not... I hope this helps you
resources :books do
resources :chapters
end
Let's assume I have the above properly nested resources. I want to create a page where I create parent book resources and another page to create the chapters resources. When creating chapters, I want users to be able to select parent books they created.
Right now I have...
protected
def find_book
#book = Book.find(params[:book_id])
end
...in the chapter controller but I believe this only works when there is already a book id present in the URL. So to create a new chapter I would have to visit "rootpath/book/book_id/chapter/new" when I want to be able to create chapters on a separate page.
Although I'm really not sure how to approach the problem, right now my plan is to put an association(?) form on the chapter creation page that links the nested resources.
The problem is, I'm really new to web development and I'm not sure if I'm approaching this right at all. How would I put a form that sends :book_id to the chapter controller? Would this method work at all? Are there more efficient ways to go at it?
I realize my questions might be a little vague but Any help would be greatly appreciated!
The dull answer is: your proposal does not make sense with only the nested route.
The nested route implies that upon accessing the chapters#new action, you already know exactly which book that should contain the chapter.
But on the bright side: you can use both nested and non-nested routes at the same time.
If you want to keep the nested route, but also provide a new and create actions that lets the user choose the desired Book for the chapter, you can add a non-nested route for Chapter creation.
For example:
resources :books do
resources :chapters
end
resources :chapters
Note that your controllers may need to be rewritten a bit to accomodate the dual routes.
If you want, you could create both resources in the same page. Look up accepts_nested_attributes_for to do that. It's really easy, once you get the hang of it.
I'm pretty new to rails, and I'm hoping you can help me understand how the following works.
At present I have a controller named projects (projects_controller.rb). From what I understand of ROR each controller has some basic (inherent) methods such as index, new, create, edit, show, etc. I would like to add a method called "help" and a view to display the help information.
At present a user can create many projects. The projects contain a set of fields that are populated by the user. I would like to add a help page that the user can access (via a link on the project screen) which explains each project field and how to best fill it out. I would like this to be an independent page (not just info displayed on the project's page).
As of now, the URL to the projects is (when editing a project): localhost:3001/projects/id/edit
I would like for the path to the help file to be localhost:3001/projects/id/help
If I want the help file to be located in the path listed above, am I correct in assuming that I need to create a new method, called "help", in the projects controller? And if so, is there something that I need to add to routes.rb to make it function? And would I use a link_to function in the Haml to create a link to it?
I'm sorry if this seems confusing or a lot of question. I appreciate your time. If you have any suggestions on whether on the right path please let me know. Thank you so much!
I think currently you have this in routes
resources :products do
end
just replace this with
resources :products do
get :help, :on => :member, :as => :help
end
And add method in controller and add view named help.erb.html(if you r using erb) in views/product folder.
you can use help_path and help_url
I understand why a Rails index method would use the plural form of a resource - we're showing all projects, for example.
And I understand why the show method would use the singular form - we only want to see one project, with a particular ID.
But I don't understand why new and create would use the plural. Is there a way to create more than one project at a time? Is there some other reasoning for using the plural here that someone could explain?
New and Create aren't plural, in the way I think about REST. Instead, I think about it like:
whatever.com is your base domain, and whatever.com/books means that you have a collection of resources each named book. The collection itself is named books.
So, when you want to create a new book, you are asking the collection for the information needed to create a new book. This becomes /books/new
When you actually create the book, you are posting information to /books. The HTTP verb is POST, so when you POST to your collection, you execute the create action.
This looks like a good starting point on REST.
I thought they were always plural. Scroll down a bit on this page for an example of the routes generated by resources :photos
Whether you're GETting a single resource or POSTing to the collection, you're still in the domain of photos. So, search the domain of photos given an id, POST a new photo to the domain of photos, etc.