I am quite new to programming and am working my way through the official Getting Started guide. This guides new RoR programmers through a practical Blog application involving CRUD articles that have many comments.
article_path is something that comes up quite often but I have no idea at all at what this does, what it means, how it is used etc.
Here are some examples of how the guide uses article_path:
<%= form_for :article, url: articles_path do |f| %>
(in app/views/articles/new.html.erb)
<%= link_to 'Back', articles_path %>
(also in app/views/articles/new.html.erb)
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
(in app/controllers/articles_controller.rb)
class CommentsController < ApplicationController
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
redirect_to article_path(#article)
end
(in app/controllers/comments_controller.rb)
I would be very grateful for an explanation, as I like to fully understand what a specific line of code does.
Thank you for your time
articles_path will produce something like this http://yourserver.com/articles which will be associated with your ArticlesController and index action.
Consequently article_path(#article) will produce something like this http://yourserver.com/articles/1234567 which will be associated with your ArticlesController and show action and produce a page for an article with id 1234567.
You also can do rake routes on the command line and see all the details
The following in your routes.rb file:
match '/articles' => 'articles#index', :via => [:get], :as => :articles
Can be invoked my mentioning articles_path. In the above example any request given to domain.com/articles will be mapped to articles#index. Instead of making request to '/articles' you can just use 'articles_path'
Another Example:
match '/articles/all' => 'articles#getAll', :via => [:get], :as => :articles_complete
Any request to yourserver.com/articles/all will be mapped to articles controller and getAll Action. Instead of mentioning '/articles/all', you can just invoke 'articles_complete_path'. I'm naming articles_complete instead of articles_all to show the convention used.
Related
I am trying to go through the 'Ruby on Rails Getting Started' tutorial(guides.rubyonrails.org) and I am running into this issue I cannot seem to figure out. I reached the point in the tutorial where I can create an article, but the redirect to see the article immediately after creation does not work and I get an error that says:
NoMethodError in Blog::ArticlesController#create
undefined method `article_url' for #<Blog::ArticlesController:0x00007f814841af20>
Here is my article controller code:
class Blog::ArticlesController < ApplicationController
def new
#article = Article.new
end
def create
#article = Article.new(params.require(:article).permit(:title, :category, :text))
#article.save
redirect_to #article # <-- This line throws error
end
def show
#article = Article.find(params[:id])
end
end
and here is my routes.rb (omitted irrelevant code):
Rails.application.routes.draw do
# <-- other get functions here
get 'blog', to: 'blog#index'
namespace :blog do
resources :articles # <-- Suggestions were to make these plural
end
root 'about#index'
end
The only deviation I have done from the tutorial is that I wanted to place the articles in a name space, as well as 1 extra value to enter in the form(category). The only suggestions for fixing my issue when I searched was to make resource into plural but my code already has this and to add #article = Article.new into def new in the controller but this addition made no difference.
I found a work around that will properly redirect after creating a new article that is the line as follows:
redirect_to :action => "show", :id => #article.id
But this doesn't seem like the "Rails Way"(Convention over Configuration), and I really don't understand why the suggested code in the tutorial is not working for me
The Rails-ey way to redirect to the proper route would be to first check in the terminal with rails routes.
There you will see if you want to route to articles#show under the namespace blog that the prefix (first column) is blog_article.
You can use this prefix with the _path method like so:
redirect_to blog_article_path(#article)
I am new to Rails and have a function in product_controller.rb
def detach
#product.photo = nil
#product.save
end
now I want to call this method from views file show.html.erb so the method get executed. How to do it ? I can see the 7 methods do get called through .find(params[id]) but that is also not clear to me.
You'll need to add a route, something like this in routes.rb:
resources :products do
member do
get 'detach' # /products/:id/detach
end
end
That will give you detach_product_path(#product) which you can use in your view. You'll probably also want a redirect in the detach method:
def detach
#product = Product.find(params[:id])
#product.photo = nil
if #product.save
redirect_to #product, notice: 'Photo was detached!'
end
end
Try changing as follow
<%= link_to 'detach_image', product_detach_path(#product) %>
I would suggest you to have a look at guides.rubyonrails.org/routing.html.
you can do as follow,
you can use match
match '/update_profile', :to => 'users#update_profile'
or
resources :users do
get 'update_profile', on: :member
end
and then you would definitely have method in your users controller
def update_profile
#user = User.find(params[:id])
if #user.save
redirect_to #user, notice: 'user updated successfully!'
end
end
I have fixed the Simon answer. However, you are still facing the problem because you are not passing the product with the path:
<%= link_to 'detach_image', detach_product_path %>
You need to pass the product to the action:
<%= link_to 'detach_image', detach_product_path(#product) %>
Otherwise, the Product.find(params[:id]) will not find any product, and the #product will get empty...
Edit to reply your questions:
1 - product_detach_path is a helper for the action detach in the controller product. There is also the product_detach_url, which does the same thing, but also includes the current host, port and path prefix. More details here.
However, it does not pass any param, so Product.find(params[:id]) cannot find the product. For this reason, you must specify what product are you trying to find. #product is defined in the show action, so it is available in your view, but you could send any other product for the detach action.... maybe the first one: product_detach_path(Product.first)
2 - the resources :products generates seven default routes: index, new, create, show, edit, update and destroy.
In order to add more routes to it, you can use member or collection. Basically, member will add a route to a product (products/1/detach), while collection will add a route to the controller, like index (products/detach). More information here.
I hope it helps...
So essentially I've setup a route to match "products/:product", which seems to respond to a page like baseurl/products/toaster and displays the toaster product. My problem is I can't seem to use link_to to generate this path, and by that I mean I don't know how. Any help on this?
There are several solutions on this one :
<%= link_to 'Toaster', { :controller => 'products', :action => 'whatever', :product => 'toaster' } %>
But it's not really Rails Way, for that you need to add :as => :product at the end of your route. This will create the product_path helper that can be used this way :
<%= link_to 'Toaster', product_path(:product => 'toaster') %>
Within your routes file you can do something like:
match "products/:product" => "products#show", :as => :product
Where the controller is ProductsController and the view is show
within the Products controller your have
def show
#product = Hub.find_by_name(params[:product])
respond_to do |format|
format.html # show.html.erb
end
end
Where whatever is in the products/:product section will be available via params.
Then, since we used :as in your routes you can do this with link_to:
<%= link_to product(#product) %>
Where #product is an instance of a product or a string. This is just an example and the param can be anything you want, the same goes for controller/action. For more info you should check out this.
Hope this helps!
I am trying to get a basic form to work and am struggling because I keep getting the error
undefined method `profiles_index_path' for #<#<Class:0x4fe1ba8>:0x4fccda0>
I have checked through and can't seem to work out where I am going wrong.
In my view (new.html.erb) I have:
<%= form_for #profile do |f| %>
<%= f.text_field :name %>
<%= f.text_field :city %>
<%= f.text_field :country %>
<%= f.text_field :about %>
<%= f.submit "Create Profile" %>
<% end %>
In my profiles controller I have:
class ProfilesController < ApplicationController
def new
#title = "New Profile"
#profile = Profiles.new
end
def create
#user = current_user
#profile = #user.profiles.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => "Welcome to your new profile!"
else
render "profiles#new"
end
end
def edit
#user = current_user
#profile = #user.profiles.find(params[:id])
end
def update
#title = "Update Profile"
#user = current_user
#profile = #user.profiles.find(params[:id])
if #profile.update_attributes(params[:profile])
redirect_to profile_path
else
render action: "edit"
end
end
def index
#user = current_user
#profile = #user.profiles.all
#title = "Profile"
end
end
And finally in my profiles model I have
class Profiles < ActiveRecord::Base
belongs_to :user
end
Any help people can offer really would be much appreciated because I am stumped. :)
Sorry forgot to include routes:
controller :profiles do
get "newprofile" => "profiles#new"
get "updateprofile" => "profiles#update"
get "profile" => "profiles#home"
end
resources :profiles, :controller => 'profiles'
The problem is indeed the way you've pluralized your model name. Don't do that. It should be a Profile, not a Profiles. There my be some work around to allow you to use a plural model name, but the answer is to stick to Rails convention rather than fighting the framework. Rename your model to Profile and the url_for helpers will understand how to correctly turn a new Profile object into a /profiles URL.
If you run "rake routes" command, do "profiles_index" appear in your routes? Usually for the index page of a model, the work 'index' is left out so the route is profiles_path
You error probably comes from a view where you've used profiles_index_path instead of profiles_path
I think it's failing due to the convention not being followed with your model name.
So I think you're problem is mostly around that you aren't following the convention on the model name, which would classically be singular, since each instance represents one profile. I think the form_for helper is trying to figure out what to do with it and failing as a result. So you have two options to try and resolve. Refactor the model name to singular (I'm not clear exacly how difficult that would be) or pass the :url paramater to form_for so it knows where to post to.
<% form_for #profile, :url => path_to_create_action do |f| %>
more information here:
I'm working with Rails 5 and I got the same error and it was specific using the word Media as my model and RoR used Medium as the plural so I got different routes when executing rake routes.
What I did to fix it was:
Delete the model I just have created.
rails d scaffold Media
Edit config/initializers/inflections.rb with:
ActiveSupport::Inflector.inflections(:en) do |inflect|
# Here you can put the singular and plural form you expect
inflect.irregular 'media', 'medias'
end
Now execute the scaffold again:
rails g scaffold Media
Now you must have everything in the way you expected. Because you have overwritten the Pluralizations and Singularizations (Inflections) in Ruby on Rails.
I hope it could be useful.
Have you tried to replace your form_for tag with the following?
<%= form_for #profile, :as => :post do |f| %>
It looks like it's trying to treat it as a GET request to "/profile". And, since it is not finding the index action, it craps out. I think forcing it to do a POST will fix this issue.
Very noob question here.
I am trying to make a digg-like website and when they click a button I want a counter to go up, just like in digg. So I did:
<%=button_to("vote", :action => "vote")%>
and then in my controller I made a action:
def vote
#article = Article.find(params[:id])
#article.votes = #article.votes + 1
respond_to do |format|
format.html { redirect_to(#article.company) }
end
end
When I do that you I get the error:
No route matches {:action=>"agree", :controller=>"companies"}
What should I do?
In a terminal type "rake routes", then look at your routes to find what path you need to use to vote for an article.
Then use
<%= button_to "Vote", vote_path(:id => article.id) %>
Just change the "vote_path" to the path in your rake routes output.
If it's not already in your rake routes file, put something like this in
match "vote/:id" => "controler_name#vote", :as => :vote
Take a look at http://guides.rubyonrails.org/routing.html#adding-more-restful-actions