adding a method to an existing controller - ruby-on-rails

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

Related

link_to 'new' action in a different controller?

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

Copy a dynamic page in a view

My knowledge of Rails is pretty basic, but I have to fix a problem in a Rails project and the programmer can not be reached. So I'm trying to fix it myself, but I'm stuck.
The project revolves around user being able to add pictures to competitions, and to be able to vote on those pictures. The plan was to have to voting on the same page as the images, but this gives a few bugs in the JS and slow performance. So I want to have the voting and the overview on two different pages.
The problem is that I can't figure out how to create another page inside the views > competitions folder and link it up with the rest of the project. The easiest solution for me would be to copy the show.html.haml and paste it like votepage.html.haml but obviously that isn't so easy.
in the view > competitions folder there's an index.html.haml file, this displays a list of current competitions and gives a admin the ability to remove, add or edit certain competitions. When a user clicks on a link to a competition this gets rendered in the show.html.haml. On this page all the images that have been uploaded in that competition are shown. On that page I want a link that refers to the voting section. When a user clicks that link it should go to the votepage.html.haml (which is 100% the same as the show.html.haml but with different styling and added javascript). For now there's no need to actually make the voting work, "faking" it through front-end is good enough.
TLDR: I want to copy/paste a page in a view, but I don't know how to hook it up to the project.
Update1. I've used the console command rails generate controller competitions votepage which created a votepage for me. I could visit this one as well on http://localhost:3000/competitions/votepage
With the following code
- #competitions.each do |competition|
#container.js-masonry
.painting.item
= link_to competition do
- competition.pictures.shuffle.each do |picture|
= image_tag(picture.image_url)
I can insert images from the competitions in the page. But the problem is that I gets images from all competitions. And not so much competitions/1 , competitions/2 etc.
What you're missing is updating the routes file so that Rails knows what you want
Views:
competitions/
show.html.haml
vote.html.haml
...
Routes:
resources :competitions do
get :vote, on: :member
end
Member makes it behave like the show action, requiring a format like competitions/:id/vote
Edit:
You want to do the routes like above, but in the controller, make sure you get the competition from the id that will get passed
Controller:
def vote
#competition = Competition.find(params[:id])
end
And then instead of looping through all the competitions, you can just take the loop out and reference #competition
The basic answer is that you also need to copy the show method from app/controllers/competitions and make a votepage method with the contents in the same file.
This guide will help explain how views get wired (by the controller) to models: http://guides.rubyonrails.org/action_controller_overview.html

ruby on rails link_to newly created page

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

Creating a rails path for a known action based on current record

As part of my template I show some automatic links which are created in the application_controller. Some of these links will offer a navigation direct from a show page to a corresponding edit page, and a few similar things.
My current code includes:
nav_links << {:name=>:edit,:url=>url_for(:action => :edit)}
This works great apart from I have child resources defined in my routes.rb file.
In this case instead of navigating to:
a/1/b/2/edit
It navigates to
b/2/edit
which isn't a valid route.
Any ideas on how to accomplish this would be much appreciated. I'm keen to avoid special case where at all possible.
A little confused - why not just use the routes resources define for you. Given that you mentioned 'child resource', I can assume you've declared these resources? If so - you should have a host of routes available to you...
Fire off 'rake routes' from the command line
Find your route
It will most likely take two arguments and look something like this (roughly):
edit_a_b GET /a/:a_id/b/:id
Just use edit_a_b_url(#a, #b)
Hope this helps.

Rails pattern to build new object related to current view/model

Rails newb question: Say I'm currently viewing the show.html for one of my classes(Dog). This class has_many Flea(s). If I put a "add new flea" link that links to new_flea_path (/fleas/new) when clicked it will build a new Flea (`#flea = Flea.new) and render flea's new.html.haml with its form fields...
But, how/where do I automatically pass in the dog_id that the flea needs to reference?
is this a routes issue? maybe /dog/3/flea/new is what I need to handle in routes? or is this a controller thing?
What you are looking for is referred to as "Nested Resources". you can read up on them here

Resources