Forward parameters in the specific order (using link_to helper) - ruby-on-rails

I want to forward parameters from one view to the another one, and this is what I managed to do. But I want to pass those parameters in the specific order. On first request, after I send the form, I get the params in the order that I want. For example:
http://www.example.com/someurl?project_id=1&start_date=2016-01-10&end_date=2016-01-20
Then, after I have those params in the view, I generate a link with link_to helper, in this kind of a way:
= link_to "link text", some_specific_path(some_id, {"project_id"=>"1", "start_date"=>"2016-01-10", "end_date"=>"2016-01-20"})
But then, the link will be generated as:
http://www.example.com/someurl?end_date=2016-01-20project_id=1&start_date=2016-01-10
So, the problem is - when I send a form, parameters get added to the url in the order of how they appear in the form. But, when you generate a link with link_to helper and path helper, then parameters are always added in the alphabetical order, no matter how they actually appear.

It is Rails bug https://github.com/rails/rails/issues/1146
also, consider send params between request in sessions.

Ok, my solution for you, but it's realy urly:
hash = {"project_id"=>"1", "start_date"=>"2016-01-10", "end_date"=>"2016-01-20"}
query_string = hash.map{|k,v| "#{k}=#{v}"}.join("&")
link_to "link text", some_specific_path(some_id) + "?" + query_string

It's good idea to define a helper here:
module ApplicationHelper
def link_to_with_sorted_params(text, path, _params)
prepared_params = _params.map { |k,v| "#{k}=#{v}" }.join("&")
prepared_link = "#{path}?#{prepared_params}"
link_to text, prepared_link
end
end
Call it
=link_to_with_sorted_params("hi", users_path, {"user" => 1, "res" => 2})
#=> hi

Related

parse form_for/form_tag to get the url or controller/action

I want to parse form_for and form_tag statements in erb files to determine which urls they post to or which controller/action will be called.
For example, given a ".html.erb" file, I want to get all "<%= form_for %>" tags out, somehow parse it, and get to know which exact controller/action pair will be called after I click to submit this form. For instance, the following file, https://github.com/jcs/lobsters/blob/master/app/views/stories/new.html.erb
line 7, "<%= form_for #story do |f| %>", can I determine which controller/action pair it will be mapped to by running some line of code? just like "routes.recognize_path 'form_for #story do |f|'" such kind of thing?
form_tag
form_tag(url_for_options = {}, options = {}, &block)
form_for
form_for(record, options = {}, &block)
Looks like I need to somehow get the url_for_options and options object out and get the url element out. Is there any easy way to do it or is there any existing tools that can achieve such functions? Does rails have any built-in functions for such thing?
i don't know if i understand your question correctly, especially the part about parsing your views etc, but you can generate urls by calling url_for.
for example in your rails console you can do the following:
include Rails.application.routes.url_helpers
default_url_options[:host] = "localhost"
url_for #user # => "http://localhost/users/1"

Rails: Generating a link

I want to generate a hyperlink through combining records from my DB. Here is an example:
token_id value is 123456789
user_name value is Peter
brand_id value is 8
The token_id+brand_id+user_name should be combined to a new array like unique_id so you'll get this as a result:
Unique_id=123456789-8-peter
Then I want to put the result inside a clickable URL, like:
example.com/?campaign=XYZ?Unique_id=<%= unique_id %>
Do you have any ideas?
It's hard to know what you are actually trying to achieve here but i'll have a guess.
For a start, that's not a valid url: the url must have only one ? as this tells it when the path ends and the parameters start. (if you want ? in param values you'll need to url encode it but i don;t think that's what you had in mind). An example of a valid url would be
http://example.com?campaign=XYZ&unique_id=123456789-8-peter
which has "/" as the path and then two parameters (campaign and unique_id)
Note that i've used "unique_id" (downcased) as the second param name: by convention param names are all downcased.
To make the link:
<% unique_id = [token_id, user_name, brand_id].join("-") %>
<%= link_to home_path(:campaign => "XYZ", :unique_id => unique_id) %>
This assumes you've defined a route called "home" which points to "/". This will need to point to some controller and default action, eg your home controller and "index" action. It also assumes that the variables token_id, user_name and brand_id have been defined somewhere.
Alternately, you might want a url like this, which loads a campaign:
http://example.com/campaigns/XYZ?unique_id=123456789-8-peter
Note the path is now "/campaigns/XYZ" rather than just "/". By convention this would call your CampaignsController's "show" action, passing "XYZ" as params[:id]. you will also get 123456789-8-peter in params[:unique_id].
To generate this link in rails using the link_to helper it might be something like
<% unique_id = [token_id, user_name, brand_id].join("-") %>
<%= link_to campaign_path(#campaign, :unique_id => unique_id) %>
this expects #campaign to have been defined.
You can add to model:
def to_param
[token_id, brand_id, user_name.parameterize].join("-")
end
More information you can find here: Friendly URLs

rails: pass 2-d array to link_to

I have a controller querys with an action send_file.
querys_controller.rb
def send_file
send_data(params[data], :filename => "query.txt")
end
in html.erb I have:
<%=link_to "send data", :controller=>"querys", :action=>"send_file", :data=>#mat, method: :post%>
By clicking on"send data" rails shows me "Bad request" due to the fact that #mat is a 2-D array and it seems I link_to cannot send such structure. How can I send my matrix to my controller ?
#mat:
[["1681", "", "02.05.1955"], ["1680", "", "02.03.1936"], ["1679", "", "26.11.1938"], ["1692", "", "15.05.1958"]]
#Tonja, to me it seems to be very strange what you are doing. First you somewhere generate an array, then pass it over using the browser again back to your application. And then you send it back to the browser in a text format?
You should not pass this array to the user, but keep it on the server. Just store it in the database. Do not pass data to the user, only when absolutely neccesary. Your current implementation also forces you to do quite some checks on the data that is passed.
In the controller method that generates the html.erb, store the #mat instance somewhere, and get the ID of the record. Pass this ID to the link_to, and use this data from the DB as parameter for the send_data call.
(Small tip: do not actually use the ID, that is not secure, but use a random value. Or even better: do not pass anything at all if you can attach the value to the current_user).
You get the Bad Request because Rails does not understand the format you request. And that is because you assemble the url yourself. Use a call like
link_to "send file", send_file_querys_path(format: :txt)
or even a
button_to ....
if it is a POST operation.
You can get the valid routes with 'rake routes'. This makes your app better testable.
I hope my answers help you to rework your code. If what you are doing is the right way, then #m_x gave you the correct pointers.
Best regards,
Hugo
when passing url arguments in the form of a hash, you should separate them from the rest of the arguments for link_to:
<%
= link_to "send data",
{controller: "querys", action: "send_file", data: #mat},
method: :post
%>
However, this will pass the data as query parameters. If you really want to pass the data as POST parameters (for example, if #mat contains a lot of data), you will have to use a form tag with a hidden field and a submit button.
IMO a more efficient approach would be to pass the parameters that were required to populate #mat, repopulate the variable server-side and use it in send_file.
The best practice in this regard is to leverage rails' format capabilities, for example :
def some_action
#mat = populate_mat(params)
respond_to do |format|
format.html
format.txt do
send_data(#mat, :filename => "query.txt")
end
end
end
(note : for this to work, you will probably have to register the txt mime type in config/initializers/mime_types.rb)
then in some_action.html.erb:
<% = link_to "send data", {format: :txt}, class: 'whatever' %>
This will will just add a .txt extension at the end of the current url, which plays nicely with the REST paradigm (one endpoint per resource, with the extension indicating the desired representation).
You can also pass the format option to any url helper, for example :
<%= link_to "root", root_path(format: :txt), class: 'whatever' %>
Try this:
link_to("Send data", send_file_querys_path(data: #mat), method: :post)

Setting dynamic link path with url parameters in rails

I'm building an app where I set links dynamically through a url parameter. I can't figure out how to make the link_to work with both a dynamic link and further url parameters.
TemplateController
def next
#template = Template.find(params[:t])
end
Next View
<%= link_to "#{#template.firstpage_link}(:t => #template.id, :prt => 1)" do %><%end%>
This is what it gives me:
http://localhost:3000/role/step2_path(:t%20=%3E%20#template.id,%20:prt%20=%3E%201)
I've tried a bunch of ways and I get either errors or this link
What you seem to be shooting for is something like
<%= link_to public_send(#template.firstpage_link, :t => #template.id, :prt => 1) do %>
public_send lets you call a public method by passing in its name as a symbol or string.
However, there may be more elegant ways to achieve this with the Rails router, as #Typpex is suggesting. If nothing else, you could clean up the view a bit with something like this in a helper:
def template_path(template)
public_send(template.firstpage_link, :t => template.id, :prt => 1)
end
And then calling that from your view.
I think you are not using link_to correctly, if you look at the link_to API
You will see that the first parameter is what you would like to be displayed and the second one is the rails path. You should pass your parameter when defining the rails path (or plain url) such as
link_to "display text", "#{#template.firstpage_link}?t=#{#template.id}&prt=1"
it would be better if you could use a rails route like
template_path(#template, prt: 1)

Ruby On Rails: using arrays with link_to

I was curious on how to use arrays in the link_to method in ruby on rails for example:
Controller:
def index
#test = [1,2,3]
end
View:
<%= link_to "test", {:action => 'index'}, :test => #test %>
When looking at the source then, I end up with something to the effect of:
test
My guess is that the array's to_string or something similar is getting called to set the value of test in the html.
My goal is to be able to have a form in which people can submit data on the page, and then once they've submitted the data and return to the page, if they click on the link the data will persist through clicking on the link.
*Ideally I would like to do this without having to pass the parameters in the url.
Thank you.
If you want to keep data you should probably use cookies. They are very easy to use, just assign a value with the following in the action:
cookies[:some_key] = "some value"
and retrieve it with this:
cookies[:some_key] # returns "some value"
However, just to clarify what link_to is doing in your example:
<%= link_to "test", {:action => 'index'}, :test => #test %>
When looking at the source then, I end up with something to the effect of:
test
The reason is that you are passing #test to the third argument in link_to, which is a hash of html attributes, hence why it's turned into one. To have it become an parameter on the link, you need to pass it with the second, eg, {:action => 'index', :text => #test}. As noted above, however, this is not necessarily the best way to tackle this and, in addition, it's usually best to also pass the controller name to link_to or, better yet, use a named route.
If I understand well, you want to keep the datas submitted by the user after they validate the form ?
Well Rails is able to do that without any of your code line needed.
Based on the supposition that you have a route resource "objects"
In your controller :
def edit
#object = Object.find_by_id params[:id]
end
def update
#object = Object.find_by_id params[:id]
if #object.update_attributes params[:object]
# The datas have been successfully saved. You redirect wherever you want to.
else
render :action => 'edit'
end
end
and in your view :
<% form_for #object do |f| %>
<%= text_field :name %>
<% end %>
When the form fails to validate, the "name" text field automatically gets the previous entered data.
If after that you still need to reload your datas, you don't need to add them as a parameter in a link tag.
You get the object in your controller and passes it's datas to the view where you display it.
I would just write a view helper that formats it into a string with good separators, like commas.
That isn't a good way to be passing along information though. Try session variables, cookies, or url-encoded variables instead.
The best match to what you are doing would be url-encoded variables, which will show up in a form similar to this:
test
My guess is that it is using Array#join.
You could try something like
:test => #test.join( ',' )
and then parse the string in your controller. But it is somewhat error prone if the user enters the same character you chose as delimiter.
But, assuming the linked page is also served by Rails, I think the best solution would be to use the flash area to store the results on the server
flash[ :submitted_params ] = params;
and in the controller for the linked page
old_params = flash[ :submitted_params ] || {}

Resources