Hard coding routes in Rails - ruby-on-rails

Let's say I have this:
<%= link_to "My Big Link", page_path(:id => 4) %>
And in my page.rb I want to show urls by their permalink so I use the standard:
def to_param
"#{id}-#{title.parameterize}"
end
Now when I click "My Big Link" it takes me to the correct page, but the url in the address bar does not display the desired permalink. Instead it just shows the standard:
wwww.mysite.com/pages/4
Is this because I hard-coded an id into the page_path? It also does not work if I use straight html like..
My Big Link
I would appreciate it if anyone could verify this same behavior and let me know if this intended or not. I need the ability to hard code :id's to specify exact pages...

Just use page_path(page). I guess the path helpers don't access the database themself (which is good), but if they are being supplied with an object and that object has a to_param method this method is being used to generate an identifier.
<%= link_to "My Big Link", page_path(page) %>

It's because you are specifying the id:
page_path(:id => 4)
You could specify the path you want in this method:
page_path(:id => "#{id}-#{title.parameterize}")
Where have you defined the to_param method? In the model?

UPDATE TO MY QUESTION ---------------------->
Thanks all for the answers. This was kind of a one off situation. My solution was to simply go with html:
My Big Link
Which produced the desired:
wwww.mysite.com/pages/4-great-title-here
I didn't want to loop through page objects and waste a call to the database for this one link. Much appreciated for all the answers though!

Related

Is there a real problem with using i.e. get method instead of put in an action through clicking on a button

For example I have button for thumbs up or I want to resend a specific mail or I change a specific enum state through clicking on a button (like published/unpublished)
Now regarding the rails implementation, I can make it work using either put, get or patch, since I only have to send a specific id.
In my opinion it seems to be best practice using patch, post or put wheter one or several attributes will change on my objects. So this seems mainly to be a convention here.
On the server side I will have to add some policies to allow only specific users to do so, but beyond adding policies are there any possible issues with not using the conventional http-method here?
One very real problem with using GET is that is supposed to be an idempotent method. Lets say the new guy creates the form:
get '/things/create', to: "things#create"
<%= form_with(model: #post, url: '/posts/create', method: :get) do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<%= f.submit %>
<% end %>
class PostsController < ApplicationController
def index
#posts = Post.all
end
def create
#post = Post.new(title: params[:post][:title])
#post.save
redirect_to action: :index
end
end
He then tries it out in the browser in and is perfectly happy with it. Mission accomplished.
His boss then attempts to test it. He creates a Post titled "This new guy might not be so bad anyways". And then he hits the back button to try creating another Post. Weirdly it just loops back to the index page. He tries it again - the only thing that happens is that the page starts to fill up with "This new guy might not be so bad anyways" and he is becomes less and less convinced that its actually true.
If you used POST, PATCH, PUT or DELETE the browser would have warned him that he is about to resend a form. Thats why GET should never change anything on the server (besides maybe your pageview stats).
It also opens up for any malicous actor to get users to create, delete or modify resources simply by fooling them into clicking a link. The malicous actor doesn't even have to got though the effort of creating a phishing site and circumventing the anti-CSRF protection that Rails provides.
There is absolutely no difference between how POST, PATCH, PUT or DELETE are treated by the client or server beyond the conventions of Rails.
But since Rails is a highly convention driven framework which adheres to a specific flavor of REST it really befits you to follow those conventions if you want to be productive and not be that new guy.
When it comes to actions beyond the classical CRUD verbs its really down to your best judgement and intent is really what matters. What does the action do? Is it updating something (PATCH)? Is it actually a separate resource? (POST /mails/1/mailouts). As you may see there is no easy answer. Just be clear and document what you're doing if you're unsure.

Checking Data from a Controller on Button Click?

I'm new to Ruby, but I have created a quiz-like site where users answer multiple-choice questions. Each question is assigned to a particular quiz, so there could be multiple questions for each quiz. I'm stumped at trying to see whether the choice selected is correct for that answer or not. All the answers were saved with a question_id referrer and a correct boolean.
I have a feeling it has something to do with link_to, but I can't figure it out.
Here is the controller I am accessing:
def check
puts "//////// //////// /////// #{#givenAnswer}"
puts "//////// //////// /////// #{#correctAnswer}"
end
Here is as near as I can get to making it work, but I get a Url error:
<%= link_to "#{#ans.content}", {:controller=>:pages,:action=>:check, :givenAnswer=>#ans.content, :correctAnswer=>params["correct#{#q.id}"]}, :method=>:get, :class => "btn" %>
The above gives a UrlGenerationError.
Both #q and #ans are created by loops in the script. They are defined properly.
Any help would be appreciated. Thanks!
As per syntax given by you for link_to you are missing closing '}' before :method option.
As long as pages controller is not under some namespace then it should generate the correct link and should not give url error.
In check action correctAnswer and givenAnswer will be available in params hash and not directly as #givenAnswer and #correctAnswer. Please see params hash in check action.

How to get "http://localhost:3000/users/current" from user_path(:current)?

I tried to practice #163 Self-Referential Association using Rails 3.2.21 and work fine almost, but I can only display
http://localhost:3000/users/1
rather than
http://localhost:3000/users/current
in URL address bar. I read and search almost all code, I only find one current:
<%= link_to "View Profile", user_path(:current) %>.
What should I do for this? It is relative to Rails 3? Thanks a lot!
The Railscast is a little unconventional, but the user_path() method, will take in a value (object, string, int, symbol) and call to_param on it. A symbol (in this case :current) will turn into "current" and the url built will be "/users/current". If you pass it a #user (User instance), the to_param method will return a "1" (the id of the object) giving you "/users/1".
I say this code is unconventional because the users_controller#show method doesn't use the ID to find the #user. It just sets it to current_user for convenience. Ryan was not trying to teach this necessarily, more about the restful friendship controller and data-modeling friendships.
Try this
<%= link_to "View Profile", users_path(:current) %>.

Passing param using link_to and UJS

I'm having a hard time understanding the proper way to pass a param using link_to and UJS.
I have the following resources:
Photos
Comments
Users
A user is trying to comment on a photo by clicking "Add Comment." When this happens a box pops up using UJS showing a form rendered by utilizing a new.js.erb file. After "Create Comment" is posted the create.js.erb file is called to handle the update, which just hides the comment box and adds the comment to a list of comments.
In my index.html.erb for my photos I am doing the following:
I specify a link to add comments passing in the id of the current photo.
<%= link_to 'Add Comment', new_comment_path( photo_id: photo.id ), remote: true %>
This gives me the url: 0.0.0.0:3000/comments/new?photo_id=1, which is what I expect.
Now my question is, how do I handle this passed parameter in my new action such that I can specify something like
#comment.photo_id = photo_id
or
#comment.photo_id = params[:photo_id]
in my comments_controller.rb?
Is there something I can do in JS that will help me save the photo_id value to my #comment.photo_id column for the comment added?
First of all I'll suggest you to start using nested routes for things like comments or likes. You will find the railscast here nested_routes_railscast
Coming back to your question, use #comment.photo_id = params[:photo_id] in your controller.
There is a better approach to accomplish this, You can have the popup already on the photo show page. In the popup you can have a form for new comment model. After clicking on the specific photo you just have get the id of that photo using javascript and copy it into the hidden field for :photo_id in the form.
Yes, you can get photo_id in params, they way you have specified.
Suppose Photo has many comments in your case.
So in your case when in you get params[:photo_id] in comments_controller
you can do:-
#photo = Photo.find_by_id(params[:photo_id])
#photo.comments.create(params[:comment])
Please read about nested resources from guides.rubyonrails.org, so you can generate create comments route in restful manner.

setting a link_to with default link label/title

I have a model named product. What i wanted to be able to do was write "product.link" in my view to generate a "link_to product.title, product". I know I can't define the "link" method in the Product.rb file (because link_to does not work there), and i don't want to write "link_to product.title, product" every time i need to create a link to the product.
I was wondering if anyone could suggest the ideal way to go about having a minimal simple way of generating links to my products.
I was also wondering if there was a way in rails to set the default label field to show when i write "link_to product" instead of what it shows now: "#<Product:0x105093f20>"
Add a helper method which does the appropriate thing:
# products_helper.rb
def product_link(product)
# Change these to taste
link_to product.name, product_path(product)
end
Now in your view you can call the following in your view:
product_link product
As for your question about # appearing in the links, this is the link_to helper calling to_s on the object for the html portion of the link. Use a helper as above to define the default text.

Resources