How to load and use root_url in Rails helper file? - ruby-on-rails

In my Rails application_helper.rb file, I have a function that need to use root_url:
def get_post_link(post)
host = root_url
post_link = host + 'posts/' + post.id.to_s
return post_link
end
But then, when I am using this function, I will now get an error like this:
NoMethodError: undefined method `posts_path' for #<Module:0x007fa8978e54a8>
I search around for solution and I stumble upon this:
include Rails.application.routes.url_helpers
But when I include this line, another error comes out which is this:
ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
I know that I could simply supply the :host parameter to the root_url to solve this problem like this: root_url(:host => "localhost:3000") but this just defeating the purpose of why I wanna use the root_url in the first place. This is because I am now just hardcoding the root_url and there is no way for the code to intelligently know whether I want the production server url or my localhost url like it originally suppose to do.
So, is there any other way to do this? So i could correctly use the root_url in my application_helper?
Thanks!

Related

Replace GET params in redirect_to request.referer

I'm trying to Replace GET params in:
redirect_to request.referer
My request.referer already contains one parameter:
http://www.foo.com/bar?par=10
When i try:
redirect_to request.referer, :par => 5
it doesn't work. It redirects to referer but doesn't change :par from 10 to 5.
When i do redirect to url_path, e.g.
redirect_to root_path, :par => 5
This works ok, redirects to:
http://www.foo.com/?par=5
So my question is how to replace params in request.referer URI. Additional question is whether should I use request.referer or :back ?
Thanks
The problem is that redirect_to ultimately just takes a string, ie the url. If you were to do something like
redirect_to edit_foo_path(#foo, :bar => "qux")
then you're using a path helper to generate that string. ie, edit_foo_path(:bar => "qux") is the helper and it will be converted to "/foo/123/edit?bar=qux" which is just a "dumb" string. If you were working with the helper you can switch the params around but with the string it's already finished, if you know what i mean.
request.referer is a string as well, so what you'll need to do is to break it down into its constituent parts, modify those parts as required, and then reassemble it into a string again. The parts in question are protocol, host, path & params. You don't need to change the protocol, host or path in this case so you can keep them the same. params will be most easily manipulated when converted to a hash. Rails has various url-processing functions which you can use here, so there's probably a few different ways of doing this. I would do this like follows, which probably isn't the most efficient.
url = URL(request.referer)
#you could get this via a regex but i'm doing it "formally" with the Url object
host_and_path = "#{url.scheme}://#{url.host}#{url.path}"
params = CGI.parse(url.query)
#now you've got params as a hash you can do what you want to it.
params["par"] = 5
new_url = "#{host_and_path}?#{params.to_param}"
redirect_to new_url
like i say there's probably more efficient (in terms of lines of code, there's no issues with it speed-wise) ways to do this, but it's useful to see the step-by-step approach anyway i guess.

Issue with Redirect not functioning in Rail 2

I have this redirection in the middle of my controller so if something isn't there, it will redirect you to a new area of the site if needed. Here is the problem. It is just ignoring the redirect in the code. It looks like this.
if conditions
redirect_to "/new/address"
end
I can't even figure out why it won't redirect, but I know it makes it into the conditional and literally just ignores the redirect. What am I missing here!?
I am using Rails 2 and Ruby 1.8
What are you seeing? Is it raising an error? Is there an error message in the console when running "script/server"? For this to work, there should be something to handle the path "new", typically a controller called "NewsController" (plural form) or some rule in the routes.rb file.
If you are seeking to create a new address, then you may be looking for something like
if conditions
redirect_to new_address_path
end
Did you try to use rails paths instead of a string path there?
Try something like
redirect_to :action => 'new'
if the method is inside this controller, or something like
redirect_to :controller => 'adress', :action => 'new'
To see if the result changes.
Don't forget that a redirect_to or render call in a Rails action do not terminate the method. Method execution continues to the end before the redirect/render is performed. So if you're looking to terminate execution of the method at that point add a return statement. The usual pattern is:
redirect_to(<my route>) and return

url_for not using default_url_options[:host] value

I've got a view for an ActionMailer that includes a few different links. I'm running it on localhost:3000 right now, and so I've set that as such in a file called setup_mail.rb in app/initializers (as indicated here):
ActionMailer::Base.default_url_options[:host] = "localhost:3000"
When I go to use url_for in the view, it doesn't seem to pull this value. If I then add :host => "localhost:3000" to each url_for tag, they work properly. But they don't work without that included.
I have another tag, project_url, which is as it appears: a link to a specified Project. This functions, including the host value, with just project_url(#project). Why would one work but not the other?
From everything I've read, setting the default_url_options[:host] in an initializer should allow me to omit the :host value in the url_for tag. Obviously, it's not the worst thing in the world to just add that value, but it seems unnecessary and it means that when I eventually host the project somewhere I'll have to go through and change that value all over the place. But worse than that, it's something that I don't understand. I'm still learning as I go here and so I'd like to know what I'm doing wrong.
The documentation is pretty clear on this
When you decide to set a default :host for your mailers, then you need to make sure to use the :only_path => false option when using url_for. Since the url_for view helper will generate relative URLs by default when a :host option isn’t explicitly provided, passing :only_path => false will ensure that absolute URLs are generated.
You could create your own helper to use instead of the url_for to force :only_path to be false
def your_url_for(options = {})
options.reverse_merge! only_path: false
url_for(options)
end
You could also monkey patch rails to force this as the default, but that's left up to you :)
This all would be in addition to adding
config.action_mailer.default_url_options = { host: "YOUR HOST" }
to config/application.rb or equivalent.
It seems :only_path option is false which is by default. so that is why you need to provide [:host] either explicitly for every tag or set default options for url_for which would apply to all tags. here is how to set default host:
put this code in your Application controller & it should work.
helper_method :url_for
def default_url_options(options)
{ host: 'localhost:3000' }
end
For more details check set url_for defaults
Instead of tampering with the global default setting which imho shouldn't be changed after initialization you can simply define a method default_url_options in your mailer just like you can do it in a controller:
class UserMailer < ActionMailer::Base
def default_url_options
{ host: Tenant.current(true).host }
end
def confirm(user)
#user = user
mail(to: #user.email, subject: t(".subject_confirm"))
end
end
You're setting the default in ActionMailer::Base, but appear to expect it to reset the default for ActionController::Base.
A <%= link_to %> inside your mailer view doesn't necessarily know anything about the fact that it's inside a mailer view.

Rails: redirect_to '#{user.role}_url' how do I accomplish this?

Is there a way in rails/ruby to simplify my routing code to be elegant like:
redirect_to user.role + _url
This way if the user is an admin they will be routed to the admin page so on so forth for other user types...
Sure!
redirect_to send("#{user.role}_url")
in ruby, the send will execute the method on the receiver, and that's exactly what you want. Usually, that would look like:
#receiver_object.send(:admin_url)
But the url-helpers work in the global namespace, so you can send to global and have it work.
Easy way to test: Add this to a controller and watch it redirect you home:
redirect_to send("root_path")
Probably the best way would be to use the url_for helper. For example.
redirect_to url_for( :controller => users, :action => user.role )
This would generate a path /users/admin or /users/guest etc.
If you want to do it a hackish way you could use
redirect_to eval("#{user.role}_url")
Be careful with that though. The reason your string isn't working is it isn't evaluated, so redirect_to "admin_url" doesn't do anything, it's just a meaningless string and redirect is expecting the string to be a URL.
If you evaluate the string it would work, because redirect_to eval("#{user.role}_url") is going to first convert "admin_url" into calling the admin_url method, which returns some path like users/admin, and THAT string is useable by the redirect method.
You can use render "#{user.role}". Just be sure to have corresponding views with the names admin.html.erb' and so on.
I really like Andrew's answer, but you could also do something like
redirect_to send(user.role.to_s + '_url')
There are several things that you could do, but nothing built in and nothing that would be significantly simpler than send("#{user.role}_url"). Be sure to use send() - otherwise it will redirect to the URL "/admin_url" instead of calling the admin_url helper.
One such other solution would be to create an action called 'home' that would redirect to the current_user's role's page. That would add an extra redirect (slightly increase the page load time), but it would make your redirects simpler
redirect_to home_url

Rails 3 change path to url

I am passing a path as a parameter, so params[:path] would be name_path(:username => #user.name (I want to pass it as a path and not a url, so putting name_url in the params isn't what I want).
Since you can only use redirect_to with a url, I need to change the path to a url before I can use redirect_to. How would I do this?
I found this method here
def path_to_url(path)
"http://#{request.host_with_port_without_standard_port_handling}/#{path.sub(%r[^/],'')}"
end
But, this was written in 2008, and I want to know if there is a better way in Rails 3?
Updated copy from original path to url post btw: also works on Rails 2
# abs or /abs -> http://myx.com/abs
# http://grosser.it/2008/11/24/rails-transform-path-to-url
def path_to_url(path)
"#{request.protocol}#{request.host_with_port.sub(/:80$/,"")}/#{path.sub(/^\//,"")}"
end
I think you can use a redirect_to with a path as long as its a route defined in the routes file for the current application. Thats seems to be the case from your question.
ie, name_path(:username => #user.name)
So the following should be valid.
redirect_to params[:path]
I ended up using
def path_to_url(path)
"http://#{request.host}/#{path.sub(%r[^/],'')}"
end

Resources