Injecting values into all link_to method calls in Ruby on Rails - ruby-on-rails

I have a strange requirement that I need to inject a value at the beginning of all local links. This is a legacy app and is quite large so I'm looking to do it under the hood, maybe with a monkey patch.
Basically if I have a link_to "Go to dashboard", dashboard_path or link_to "Create a new Job", new_job_path that they would both generate links that look like "/some_value/dashboard" and "/some_value/jobs/new"
Tried a few things and they all have failed. Any ideas?

You can try something like this in your helper instead of monkey patching link_to.
def custom_link_to(link, url, opts={})
url = "append_here/"+url
link_to(link, url, opts)
end
Now you can call this action instead of calling link_to wherever applicable and also use link_to in case if you don't want to override.
custom_link_to("Go to Dashboard",dashboard_path,{})
UPDATE
In case of overriding everything, something similar to this might be helpful - Monkey patching Rails

Related

Rails current url helper

Apologies for such a simple question, but I couldn't been able to solve it myself after hours since my RoR knowledge is basically nonexistent. In the Rails application I'm working with, has been used a navigation helper to highlight active menu:
def nav_link(link_text, link_path, ico_path)
class_name = current_page?(link_path) ? 'active' : nil
content_tag :li do
link_to(link_path, class: class_name) do
image_tag("icons/#{ico_path}.svg") + content_tag(:span, link_text)
end
end
end
The circumstances have changed and current_page? is no longer a viable option, since routing now handled on the front-end. Is there a way to achieve the same functionality by retrieving, for instance, current url and check it against link_path?. I've tried a lot of things with different helpers like request.original_url, but to no avail.
request.original_url should work according to the documentation.
Returns the original request URL as a string
http://apidock.com/rails/ActionDispatch/Request/original_url
You could also try string concatenation with different variables.
request.host + request.full_path
If that doesn't work either, you could try
url_for(:only_path => false);
Use
request.url
http://api.rubyonrails.org/classes/ActionDispatch/Http/URL.html#method-i-url
or
request.path
http://www.rubydoc.info/gems/rack/Rack/Request#path-instance_method
You'll want to look at the active_link_to gem:
def nav_link(link_text, link_path, ico_path)
content_tag :li do
active_link_to link_path do
image_tag("icons/#{ico_path}.svg") + content_tag(:span, link_text)
end
end
end
Unlike the current_page? helper, active_link_to uses controller actions and model objects to determine whether you're on a specific page.
current_page? only tests against the current path, leaving you exposed if you're dealing with obscure or ajaxified routes.
--
I was going to write about how current_page? works etc, but since you mentioned that it's nonviable, I won't. I would have to question why it's nonviable though...
routing now handled on the front-end.
Surely even if you're using something like Angular with Rails, you'd have to set the routes for your app?

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) %>.

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.

link_to custom action but wrong method?

all, I'm trying to get a custom action to work with a put method: in the
in _post.html.erb i have a link_to statement:
<%= link_to 'End now', post, :method => :put, :action => endnow %>
routes.rb contains:
resources :posts do
member do
put :endnow
end
and posts_controller.rb looks like:
class PostsController < ApplicationController
helper_method :endnow
[.. code for create, edit, destroy, etc ..]
def endnow
puts params
end
end
rake routes's relevant line looks like:
endnow_post PUT /posts/:id/endnow(.:format) posts#endnow
However, the action endnow helper doesn't run when clicking on this link.
Strangely, it does run with an index action (which i can tell from the puts command.
Of course, eventually the code for endnow will update #post, but for now, it just doesn't run properly.
Maybe i'm going about this the wrong way - all I'm trying to achieve is to update #post upon clicking the link to that post, and before showing it.
Any ideas / Alternatives?
Why not use the route helper method provided to you? Change your link to
<%= link_to 'End now', endnow_post_path(#post), method: :put %>
Things you're doing wrong:
If you want to specify the :action, use the Symbol for the action (you're missing a colon). :action => endnow should be action: :endnow
I will assume you have a #post instance variable you're passing from your controller to your action. You should be using that instead of post (unless you do in fact have a local post variable you're omitting from your code)
You are using endnow as an action; you should remove the helper_method :endnow line in your controller because it's not something you want to/should be accessing from your view.
This can all be avoided by using the route helper (for endnow_post you'd append _path to get the local route path: endnow_post_path), and pass in your #post as an argument.
Because you're trying to do a PUT request, you must make sure you have something like jquery-ujs included in your asset pipeline to convert these links to form submissions behind the scenes; browsers don't support PUT via the click of a link on their own.
As for why you're getting the template error when you get your link_to working, Rails is telling you that you need to create a app/views/posts/endnow.html.erb file. Your action has only puts params which does not terminate execution, leaving Rails to assume you still are trying to render some endnow.html.erb template.
Are there other ways to do what you're trying to do (change a single attribute of a specific model)? Sure. Are there better ways? That's pretty subjective; it may not be the most RESTful way, but it's arguably easier to deal with (if for example there are very specific authorization rules to check before updating the attribute you are modifying in endnow. Does the way you've started fleshing out work? Absolutely.
Finally, as a bump in the right direction, after you fix your link_to and remove the the helper_method as I have described above, your endnow action might look like this:
def endnow
post = Post.find!(params[:id])
post.some_attribute_here = some_new_value_here
post.save
redirect_to :root and return # <- this line sets a redirect back to your homepage and terminates execution, telling rails to do the redirect and **not** to render some endnow.html.erb file
end

Helper for edit/show/destroy Link with an image

i am trying to make nice helpers so that i can use these style:
edit(category)
destroy(post.comment.first)
show(#user)
and we get the selected link with a nice image.
can anyone tell me if i am doing it right or is there a better magical rails way to get the url?
def show(object)
link_to image_tag("admin/show.png"), eval("admin_{object.class.to_s.downcase}_path(# {object.id})")
end
def edit(object)
link_to image_tag("admin/edit.png"), eval("edit_admin_#{object.class.to_s.downcase}_path(#{object.id})")
end
def destroy(object)
link_to image_tag("admin/destroy.png"), eval("admin_#{object.class.to_s.downcase}_path(#{object.id})"), :method=>:delete, :confirm=>"Do you really want to delete this?"
end
this is working fine but i am looking for the magic rails way :-)
replace eval with send, and replace downcase with underscore which is rails' convention
send("admin_{object.class.to_s.underscore}_path", object.id)
BTW, rails can do these for you:
# equals to your `show(object)`
link_to image_tag('admin/show.png'), [:admin, object]

Resources