Question has many Comments.
A URL "questions/123" shows a question.
A URL:
"questions/123#answer-345"
shows a question and highlights an answer. 345 - is id of Answer model, "answer-345" is id attribute of HTML element.
I need to override "answer_path(a)" method to get
"questions/123#answer-345"
instead of
"answers/345"
How to do it ?
All url and path helper methods accept optional arguments.
What you're looking for is the anchor argument:
question_path(123, :anchor => "answer-345")
It's documented in the URLHelper#link_to examples.
Using this argument, you should be able to create an answer_path helper via:
module ApplicationHelper
def answer_path(answer)
question_path(answer.question, :anchor => "answer-#{answer.id}")
end
end
Offering a solution which covers more areas (works not only in views but also in controller/console)
module CustomUrlHelper
def answer_path(answer, options = {})
options.merge!(anchor: "answer-#{answer.id}")
question_path(answer.question, options)
end
end
# Works at Rails 4.2.6, for earliers versions see http://stackoverflow.com/a/31957323/474597
Rails.application.routes.named_routes.url_helpers_module.send(:include, CustomUrlHelper)
Related
I'm using rails 4.2.5.
And in rails API (for v4.2.5.2) I see this helper:
number_to_delimited(number, options = {})
Formats a number with grouped thousands using delimiter (e.g., 12,324). You can customize the format in the options hash.
http://api.rubyonrails.org/classes/ActiveSupport/NumberHelper.html#method-i-number_to_delimited
But when I using this help in my views, it throws an error:
undefined methodnumber_to_delimited' for #<#:0x0000000b091b30>`
Other helpers, such like number_to_currency, all works well. What's wrong with me?
Try to call ActiveSupport::NumberHelper instead.
ActiveSupport::NumberHelper.number_to_delimited(12345678)
=> "12,345,678"
Or you could do also with this:
include ActiveSupport::NumberHelper
number_to_delimited(12345678)
=> "12,345,678"
UPDATE:
I see you said in comment above that you're using haml code and you can do it like:
= ActiveSupport::NumberHelper.number_to_delimited(12345678)
Or
- include ActiveSupport::NumberHelper
= number_to_delimited(12345678)
Just include the ActiveSupport::NumberHelper in the ApplicationHelper.
module ApplicationHelper
include ActiveSupport::NumberHelper
end
Then you can directly use all the number helpers in your views.
<%= number_to_delimited(12345678) %>
number_to_delimited is a method in ActiveSupport::NumberHelper which cannot be used in the view directly.
Rails provides a couple of number helpers in ActionView::Helpers::NumberHelper which are delegated the methods in ActiveSupport::NumberHelper.
number_to_currency
number_to_human
number_to_human_size
number_to_percentage
number_to_phone
number_with_delimiter
number_with_precision
For example, if you want to delimit the number, you should call number_with_delimiter instead, which will call number_to_delimited in the ActiveSupport::NumberHelper.
# File actionview/lib/action_view/helpers/number_helper.rb, line 244
def number_with_delimiter(number, options = {})
delegate_number_helper_method(:number_to_delimited, number, options)
end
Hope that make sense. Cheers.
I would like to redirect a path in routes using the following lines:
get 'privacy_policy', :controller => :pages, :as => 'privacy_policy'
get 'privacypolicy.php' => redirect(privacy_policy_url)
So that /privacypolicy.php gets redirected to the correct page defined right above it.
However, it's throwing the following error:
undefined local variable or method `privacy_policy_url'
So I'm guessing one cannot use URL helpers in routes.rb. Is there a way to use URL helpers in the route file, and is it advisable to do so?
I know I'm a little late here, but this question is one of the top hits when googling "use url_helpers in routes.rb", and I initially found it when I had stumbled upon this problem, so I'd like to share my solution.
As #martinjlowm mentioned in his answer, one cannot use URL helpers when drawing new routes. However, there is one way to define a redirecting route rule using URL helpers. The thing is, ActionDispatch::Routing::Redirection#redirect can take a block (or a #call-able), which is later (when the user hits the route) invoked with two parameters, params and request, to return a new route, a string. And because the routes are properly drawn at that moment, it is completely valid to call URL helpers inside the block!
get 'privacypolicy.php', to: redirect { |_params, _request|
Rails.application.routes.url_helpers.privacy_policy_path
}
Furthermore, we can employ Ruby metaprogramming facilities to add some sugar:
class UrlHelpersRedirector
def self.method_missing(method, *args, **kwargs) # rubocop:disable Style/MethodMissing
new(method, args, kwargs)
end
def initialize(url_helper, args, kwargs)
#url_helper = url_helper
#args = args
#kwargs = kwargs
end
def call(_params, _request)
url_helpers.public_send(#url_helper, *#args, **#kwargs)
end
private
def url_helpers
Rails.application.routes.url_helpers
end
end
# ...
Rails.application.routes.draw do
get 'privacypolicy.php', to: redirect(UrlHelperRedirector.privacy_policy_path)
end
URL Helpers are created from the routes. Therefore they won't be usable when drawing new routes.
You will have to use gayavat's approach.
-- or --
Redirect using the exact URL like http://guides.rubyonrails.org/routing.html does.
edit:
If it's more than just the one '...php' route, you might want to consider making a redirect controller. Take a look here, how to se it up: http://palexander.posterous.com/provide-valid-301-redirects-using-rails-route
Inside your routes file, you should add this at the bottom, so it doesn't interfere with other routes:
get '/:url' => 'redirect#index'
Something like:
get 'privacypolicy.php' => "privacy_policy#show"
Imagine a blog with posts and comments. An individual comment's URL might be posts/741/comments/1220.
However, I'd like to make the URL posts/741#1220, or even posts/741#comment-1230.
What's the least intrusive way of doing this, so that redirect_to comment_path(my_comment) points to the correct URL?
You could simply use
redirect_to post_path(comment.post, :anchor => "comment-#{comment.id}")
to manually build the URL with the anchor. That way, you can still have the absolute URL to your comments as posts/:post_id/comments/:comment_id in your routes. You can also create a helper method in e.g. application_controller.rb
class ApplicationController
helper :comment_link
def comment_link(comment)
post_path(comment.post, :anchor => "comment-#{comment.id}")
end
end
Prefer to keep your anchor builder in one place.
class Comment
...
def anchor
"comment-#{id}#{created_at.to_i}"
end
end
then
post_path(comment.post, :anchor => comment.anchor)
Adding the created_at.to_i obscures your data a bit more and doesn't harm anything.
I want to add article's title to its url similarly to SO URLs. I was suggested to use the following setup in answer to my another question
# routes.rb
match '/articles/:id/:title' => 'articles#show', :as => :article_with_title
# articles/index.html.erb
link_to article.title, article_with_title_path(article, :title => article.title.downcase.gsub(/[^a-z0-9]+/,' ').strip.gsub(/\s+/,'-'))
It works, however I find it a bit redundant. Is there a way to make it nicer? What about an additional universal method to handle multiple routes?
match '/articles/:id/:title' => 'articles#show'
match '/users/:id/:name' => 'users#show'
etc.
Remarks:
Currently the following routes work fine: /article/:id/:action, /article/:id/:title with a condition that article cannot have titles edit, show, index, etc.
I believe friendly_id is unnecessary here, since the routes contain :id explicitly.
As I see, SO uses different routes for questions /question/:id/:title, /posts/:id/:action and for users /users/:id/:name, /users/:action/:id
Just override to_param in your models. Untested example from memory:
def to_param
self.id + "-" + self.name.parameterize
end
this approach means you don't have to change the router, and can also keep using Model.find(params[:id]) or similar.
Basically what the Railscast mentioned in another answer does, and the core of what friendly_id does too.
Ryan Bates did an excellent screencast on using the model's name, or any other attribute, in the url instead of the id.
I have a particular set of views relating to one of my controllers, whereby I want any call to *_path or *_url to append a set of parameters.
Is there some magic method I can override that will let me do this? I have no idea where in the Rails code the *_path or *_url methods are even handled.
Edit for clarity: I'm looking for a way to do this such that I don't have to modify every link in every view where this needs to occur. I don't want every coder who touches this set of views to have to remember to append a parameter to every link they add to the page. The same parameter should be appended automatically. I consider a change to the *_url or *_path call a failure. Similarly, having to override every *_url or *_path call is considered a failure since a new method would have to be added/removed whenever a new link is added/removed.
You can do this by overriding url_for since all the routing methods call it.
module ApplicationHelper
def url_for(options = {})
options.reverse_merge!(#extra_url_for_options) if #extra_url_for_options
super
end
end
Now all you need to do is use a before_filter to set #extra_url_for_options to a hash to force all urls.
class MyController < ApplicationController
before_filter do { #extra_url_for_options = { :format => 'html' } }
end
Note that this will force all links to use the extra options.
Thanks to Samuel's answer, I was able to create a final working solution via a new helper, which I've included below.
module ExampleHelper
def url_for(options={})
options = case options
when String
uri = Addressable::URI.new
uri.query_values = #hash_of_additional_params
options + (options.index('?').nil? ? '?' : '&') + uri.query
when Hash
options.reverse_merge(#hash_of_additional_params)
else
options
end
super
end
end
You can try to use the with_options method. In your view you can do something like
<% with_options :my_param => "my_value" do |append| -%>
<%= append.users_path(1) %>
<% end %>
Assuming you have the users_path of course. my_param=value will be appended to the url
You could make a helper method:
def my_path(p)
"#{p}_path all the parameters I want to append"
end
and in the view use
<%= eval(my_path(whatever)) %>
Eval with give you dynamic scope, so every variable available in your view can be used in the helper. If your parameters are constant you can get rid of eval calls.