Simple link_to from root_url - ruby-on-rails

I have a very simple view link_to problem no error message just a strange dot in url "http://0.0.0.0:3000/.Hire" not sure why the dot is there between the root url and Hire?
link_to:
<%= link_to page.name, root_url(page.name) %>
The routes are fine if I type manually: http://0.0.0.0:3000/Hire
I get taken to the right page but the link_to is just wrong.
I would be grateful for any help.
Many thanks
Dan

root_url isn't supposed to be given this kind of parameters. It's logic it's failing.
Run rake_routes in your console to get the proper names of your routes.
One ugly workaround to fit your needs would be:
<%= link_to page.name, root_url + page.name %>
One last question: why do you use root_url instead of root_path?
The former tend to uselessly pollute the views.

Related

How do rails forms work without a model?

I am trying to challenge my learning by creating a simple project using rails forms, however I have gotten really stuck and can't find any information that seems to help online.
What I am trying to do:
I want to create a rails application with no model (so no persistence of data). Simply put I want a user to enter a Soundcloud URL which then gets transferred to the controller where I can do more logic. Essentially I am really trying to understand the connection between the Rails form and the controller in rails. I have spent all day reading about HTML forms, as well as googling this exact question without really fully getting it.
I understand there are different form helpers, but what I cannot seem to understand is how to use these without a model. My biggest hang up right now is I cannot get the form values transferred to the controller. I thought I understood RESTful routes, PUT/GET etc.. but this has made me super frustrated that I cannot seem to get my head around this. Any advice is super appreciated.
The code:
Below is the specific code I am struggling with, currently when I get submit the form it crashes giving me an error based on routes, and that's where I am stuck.
Problem code is found in the _form.html.erb file in views:
<%= form_tag '/show' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
Routes.rb:
Rails.application.routes.draw do
resources :soundcloud_query
root 'soundcloud_query#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Error:
Routing Error
No route matches [POST] "/show"
rake routes output:
Prefix Verb URI Pattern Controller#Action
soundcloud_query_index GET /soundcloud_query(.:format) soundcloud_query#index
POST /soundcloud_query(.:format) soundcloud_query#create
new_soundcloud_query GET /soundcloud_query/new(.:format) soundcloud_query#new
edit_soundcloud_query GET /soundcloud_query/:id/edit(.:format) soundcloud_query#edit
soundcloud_query GET /soundcloud_query/:id(.:format) soundcloud_query#show
PATCH /soundcloud_query/:id(.:format) soundcloud_query#update
PUT /soundcloud_query/:id(.:format) soundcloud_query#update
DELETE /soundcloud_query/:id(.:format) soundcloud_query#destroy
root GET / soundcloud_query#index
Github link:
https://github.com/gaelant/simple_soundcloud_app/commit/09c4c4df524bb721a0f472b4378cd8c1ff18177f
Note: I understand this is a basic question but I have just gotten really confused with this. I know the way the code above is written is not correct, but I have tried so many different things and I just don't understand what is going on, or if this is even possible without a model.
Your /show form action points to nowhere. rails routes shows you which url is valid and to which controller#action each of them lead.
The correct form action would be
<%= form_tag '/soundcloud_query' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
A far more better way is to use the url_helpers available through your defined ressource in Routes.rb
Doing so your form action would look like this
<%= form_tag soundcloud_query_index_path do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
The hardcoded and the url_helper based solution will route your request to a controller class named SoundcloudQuery where the action create will be called. Inside this action you have to put all needed logic.
It's also possible do define that /show should point to a specifc controller and action. This would look like this.
post '/show', to: 'mycontroller#myaction', as: 'mypathnameforhelper'
A much more better explanation with many examples about routes and how to use them can be found in this quite good guide.
Rails Routing from the Outside In
Hint: You should stay close to the ROR naming conventions. Controllers should have pluralized names. So you should define your routes like this:
Rails.application.routes.draw do
ressources :soundcloud_queries
root 'soundcloud_queries#index'
end
and then rename your controller class and file accordingly into SoundcloudQueries and soundcloud_queries.rb. But this is not mandatory.
I think in this case you should not use the url in the form_tag but the controller action.
Let's say you've got a view called my_form.html.erb and a submit_form method in your soundcloud_controller.rb
def submit_form
params[:soundcloud_url] your logic
end
I'd set up the routes like this:
get 'soundcloud_query' => 'soundcloud_query#my_form' // didn't want to use 'resources' but it doesn't matter
post 'soundcloud_query' => 'soundcloud_query#submit_form'
The form would then look like:
<%= form_for :this_doesnt_matter, action: :submit_form do |f| %>
<%= f.text_field :soundcloud_url %>
<%= f.submit %>
<% end %>

How to create a href tag with link_to and action 'create'

I want to create a href tag like href=contacts/create. In my contacts_controller, I have a create GET action. I know this is against rails convention. I still need to create the above link using options = {controller=> 'contacts', action=>'create'}. It works for any other arbitrary action name
You can the hardcoded path option:
<%= link_to "Create", "contacts/create" %>
or the Rails generated path option:
<%= link_to "Create", { controller: "contacts", action: "create" } %>
This is not just against Rails' convention, but against sounds HTTP usage. This often causes serious problems that you can't predict in advance. Web crawling is just one of them, where something like the Google bot accidentally creates a new contact in your database, simply by crawling the page. Or script kiddies who find you have a create link, and send 100,000 clicks to it in quick succession.
Numerous other issues happen like this, including, at one well-known time, Google Chrome pre-fetching GET urls from the page to "speed up the user experience"; this was felt far and wide by sites that had used this technique. It's not an idle warning or a style issue: this can have a disastrous impact on your site.
First off this is really bad idea since GET requests should be idempotent. You're not just flouting convention - you're setting yourself and your users up for a really bad time since for example pressing the back and forward buttons will cause resources to be created - over and over. And there is guaranteed a better way to solve whatever you are trying to do such as:
# a "discrete form"
<%= button_to "Create contact", contacts_path, method: :post %>
# or use the rails ujs
<%= link_to "Create contact", contacts_path, method: :post %>
If you ABSOLUTELY have do this:
Rails.application.routes.draw do
get "contacts/create"
end
You can now do:
<%= link_to "Create", { controller: 'contacts', action: 'create' } %>
Congratulations, you broke the internets.
Like you mentioned, this is against rails convention, but if absolutely necessary, you can do this from your controller:
options = {controller=> 'contacts', action=>'create'}
view_context.link_to url_for(options)
If you need the href to only be the path, you can do:
options = {controller=> 'contacts', action=>'create'}
view_context.link_to url_for(options.merge(only_path: true))

Rails 4 Link_ to Create New Record - Request Type

I am on Rails 4.
Just created a Favorite model & controller in which users can favorite articles. I have it set up so when a user clicks on the link, it routes to the favorite action inside of the favorites_controller. Right now, it is a get request, and inside of the action it is simply creating a new favorite.
My question is... is it ok that this is a get request? I feel like maybe a post request would be better (as forms use post to create things), but since there is no form in this case I decided a get request would be fine. Is this ok? or frowned upon?
here is the link_to in my view:
<%= link_to favorite_path(title: #article.title, id: #article.id) do %>
<span class="glyphicon glyphicon-star-empty"></span>
<% end %>
and the action it routes to in the controller:
def favorite
current_user.favorites.create(article_id: params[:id],
article_title: params[:title])
flash[:success] = "You added this page to your favorites."
redirect_to request.referrer || root_url
end
and my routes.rb:
get 'favorite' => 'favorites#favorite'
Everything works fine, just want some clarification as to the get request and if this is the best way to achieve what I am doing. If there is already documentation on this, please send it my way.
No, you shouldn't use a get request to create things or change states.
The reason is simple: Searchengines will follow links and trigger that action. Or some browsers may preload links to speed things up. In both case you will create records although the user never chose to click the link.
Instead just tell Rails to use some javascript to fake a post request (note the method: :post part):
<%= link_to(favorite_path(title: #article.title, id: #article.id),
method: :post) do %>
<span class="glyphicon glyphicon-star-empty"></span>
<% end %>
Read the doc about link_to for details.

How to get root path of rails app

I am novice to rails. I have been using LAMP for a long time. I am looking for something like {{URL::to('/')}} from Laravel.
I DO NOT want to use link_to which creates entire anchor tag as it defeats the purpose of isolating views. I want to get a value to put in href tag.
This is a link
Rails has has the root_path and root_url helpers
You also seem quite confused about link_to it does not compromise the "isolation" of your views. Its a helper method which makes it possible to create very dynamic html without doing a lot of interpolation.
<%= link_to t('home'), root_path, class: 'btn btn-success' %>

Identifying objects in Rails - Sometimes with :id and sometimes with the object itself?

another pretty general question about Ruby on rails:
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
Looking at the find method, I call it with the parameter id (which is incoming through the REST request, I guess)
Now here
<%= link_to 'Destroy Comment', [comment.post, comment],
method: :delete,
data:{confirm: 'Are you sure?' } %>
I assemble the route with the id of both comment.post + comment. To me it seems like the comment.post.id and comment.id are given implicitly (magic^^), which is fine for me, but I tried to code it, and I get an exception.
Why is it that way? And can somebody guide me to the right part of the documentation where exactly this behavior is described? Im pretty lost with all this smart and automatic stuff ruby does....
Thanks!
You're confusing two very different things.
This is doing a request to ActiveRecord to find an instance of Post with a matching id:
Post.find(id)
This next line is using the built in UrlHelper to construct an HTML link in your view for the given resource:
link_to 'Link Text', resource
In your particular case, you specify the :method as being :delete. Through the configuration in your routes.rb file, rails then maps this DELETE request for a [POST, Comment] nested resource to the posts_comment_path and passes in the post_id for comment.post and the id for comment.
This isn't so magic if you dig through the Rails source code a little. The link_to documentation states that the second argument can accept any valid options accepted by url_for. (click here for link_to docs)
The url_for documentation (available here) says this:
<%= url_for(#workshop) %>
# calls #workshop.to_param which by default returns the id
# => /workshops/5
# to_param can be re-defined in a model to provide different URL names:
# => /workshops/1-workshop-name
So, not so magic really. It's definitely worth spending a little time following the chain of calls that rails makes when you call something like link_to as it demystifies a lot of what you initially see as quite complex.

Resources