url_for not using default_url_options[:host] value - ruby-on-rails

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.

Related

How to load and use root_url in Rails helper file?

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!

Rails: configuring a form action's host using custom URL from settings

I have a Rails app that I am feeding cross domain in production. It needs absolute references. Because of this, I have enabled the following in my config/environments/production.rb:
config.action_controller.asset_host = "http://myapp.herokuapp.com"
That works fine for images and resources but my input form that looks like this:
<%= form_tag('/plans/collapse_plans', :method => 'post', :remote => true ) do %>
is still getting this in the console:
Failed to load resource file://localhost/plans/collapse_plan
How can I change it so that form action will automatically include the specified host, instead of defaulting to localhost? Can I set this anywhere in config?
This seems like it will work:
https://github.com/binarylogic/settingslogic
Then I can just do:
<%= form_tag mysettings.myspecifiedhost + plans_collapse_plans_path, :method => 'post', :remote => true do %>
I may be on the wrong track here, but:
Asset host is not your application's host, asset host is a host that serves you /app/assets folder and this is configurable so you can set up a CDN for example, it's not intended for hosting action points.
If you want to target the full url of your own host use rake routes to get the route name corresponding to /plans/collapse_plans which probably looks something in the lines of plans_collapse_plans and then you can use plans_collapse_plans_url and rails will render the correct full URL for you.
If you're using the default host name rails provides automagically this will "just work", i.e.
[2] pry(#<#<Class:0x000000048fd780>>)> account_edit_url
=> "http://dev:3000/account/edit"
If this doesn't "just work", you can override all url helpers in the app by overriding default_url_options in your ApplicationController:
def default_url_options
{:host => HOST}
end
and be sure to set the HOST constant in your application's environment, for example:
[1] pry(#<#<Class:0x00000005047d10>>)> account_edit_url
=> "http://o7ms:3000/account/edit"
If you need to override this just in certain situations you can leave the ApplicationController alone and do:
[3] pry(#<#<Class:0x000000048fd780>>)> account_edit_url(host: MY_HOST_FOR_THE_OTHER_THINGY)
=> "http://foo:3000/account/edit"
In all cases you'll set up a config option in one place and all endpoints in the app will adjust.
EDIT
If you want to go fancy,
see default_url_options and rails 3,
by overriding url_options you may be able to implement pretty calls like account_edit_url(ajax_host: true), the url_options method would look something like this if this works:
def url_options
options = super
if super.delete(:ajax_host)
{host: AJAX_HOST}.merge(options)
else
options
end
end
what you are trying cannot be done normally for ajax calls.
see http://en.wikipedia.org/wiki/Same-origin_policy
Two approaches:--
1.) <%= form_tag root_url + plans_collapse_plans_path, :method => 'post', :remote => true do %>
concatenation:-- root_url + plans_collapse_plans_path
2.) in config/environments/production.rb
MyApp::Application.configure do
# general configurations
config.after_initialize do
Rails.application.routes.default_url_options[:host] = 'root_url' #'localhost:3000'
end
end

How to get full asset path in rails model

I'm using gmap4rails in my application which says to specify a marker you should define a method in your model. But how can i get full image url for that?
Now I have the following code in my model
def gmaps4rails_marker_picture
{
"picture" => helpers.asset_path("marker.png"),
"width" => 20,
"height" => 33
}
end
def helpers
ActionController::Base.helpers
end
But this only give me path for an image?
I've also tried to do it like this
Rails.application.routes.url_helpers.root_url + helpers.image_path("marker.png")
but that gives me an error:
Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
Any way to make this work?
Look at How to set config.action_controller.default_url_options = {:host = '#''} on per environment basis.
You need to set Rails.application.routes.default_url_options or to pass :host option to root_url(host: 'foo.bar')
To set different host option for different environments you can use ./config/environments/xx.rb files

Dynamically preset a url for development and production environments

I'm creating a password reset functionality for my site in rails and in my mailer password_reset.text.erb file I'm currently sending
http://localhost:3000/password_resets/<%=#user.password_reset_token%>/edit/
in my development environment. This will hit my controller for password reset and redirect the user to edit the password if the token matches with the saved model.
However, I'd like to configure this dynamically so when I deploy to heroku it will know to change that to mywebsite.com/password_resets/...
How would I do this?
EDIT:
def password_reset(user)
#user = user
mail(to: user.email, subject: "Bitelist Password Reset")
end
Typically I configure the host information for the mailer in an appropriate config/environment file.
config.action_mailer.default_url_options = { :host => "example.com" }
You can take a look at the "Generating URLs" section of this page: http://rails.rubyonrails.org/classes/ActionMailer/Base.html
With that configuration set typical routing structures seem to work quite nicely. I am not 100% positive what routes will be available in your situation so you may still need to construct the full URL somewhat manually to include the reset token component.
To generate the actual URLs you can potentially use named routes if your routes are set up in a way that you have a named route that takes a user token. i.e.
<%= edit_password_resets_url(#user.password_reset_token) %>
If you do not have the token integrated into an existing route you may need to manually build the URL:
<%= "#{url_for(:controller => 'password_resets', :action => 'whatever_action_this_is')}/#{#user.password_reset_token}/edit/" %>
or even build it completely manually using default_url_options[:host] and then add the rest that you have above.
If need be you could also set the host at request time although that may be overkill (and will not be thread safe).
def set_mailer_host
ActionMailer::Base.default_url_options[:host] = request.host_with_port
end

Handling mix of HTTP and HTTPS links on a page

My setup: Rails 3.0.9, Ruby 1.9.2
My app requires that only a certain part of my site be SSL protected and the rest not. In case anyone thinks this isn't normal behavior, check out Amazon. When merely browsing for products, it's in HTTP mode, during checkout, it switches to HTTPS. Even in the middle of a secure checkout transaction, there are several other links on the same page that are HTTP only.
I looked at ssl_requirement gem and decided not to use it because it isn't a complete solution for my needs. I ended up setting up specific SSL routes like
resources :projects do
resources :tasks, :constraints => { :protocol => "https" }
end
In my view code, for HTTP specific links
<%= link_to 'Projects', project_url(#project, :protocol => "http") %>
and to handle HTTPS specific link
<%= link_to 'Task', new_project_task_url(#project, :protocol => "https") %>
I understand this isn't the cleanest way but it's what I have decided to do. The problem with this setup is how to properly set both HTTP and HTTPS links on every page. There is a proposed solution here but it requires wholesale changes _path to _url and I prefer to avoid that if at all possible. The solutions involves adding this method in
application_helper.rb
module ApplicationHelper
def url_for(options = nil)
if Hash === options
options[:protocol] ||= 'http'
end
super(options)
end
end
So my question is it possible to change this method or another one to change _path calls to explicit urls so I can use the above method to set the proper protocol.
you could try this, although I'm not 100% sure it works:
Use the proposed changes from the stackoverflow answer
Add this to application_controll.rb:
class ApplicationController < ActionController::Base
def url_options
{ :host => request.host }.merge(super)
end
end
According to the Docs it should add the full url even if you use _path:
:only_path - If true, returns the relative URL (omitting the protocol,
host name, and port) (true by default unless :host is specified).
My app requires that only a certain part of my site be SSL protected and the rest not.
That's your faulty assumption. The secure premise is that if some of your app requires SSL, then all of your app requires SSL. The correct assumption then is that your entire app requires SSL.
If your app requires SSL, then you should use something simple like rack-ssl which sets the HSTS header and enforces the secure flag on cookies in all responses.

Resources