Rails: Generating a link - ruby-on-rails

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

Related

What does a link_to helper expand to when passed an array with a symbol and object in Rails?

In Rails, (specifically in ActiveAdmin) what does a link_to helper with an array passed as the second parameter do? Where's the documentation for this?
I have this code:
index pagination_total: false do
column :name, :sortable => :first_name do |user|
link_to user.full_name, [:admin, user]
end
What does that do? What does [:admin, user] do here?
One confusing thing here is that my ActiveAdmin panel is defined as:
ActiveAdmin.register Promotions::User, as: "User" do
So the link actually comes out prepended with the module like so:
admin_promotions_users_path which I don't want. This causes an error since the as: overwrites the ActiveAdmin path_helper. What I want is:
admin_users_path.
In short, I think the error here is that I don't know what a link_helper expands to when passed an array with a symbol an object.
According to Ruby on Rails - link_to method, the method signature is link_to(body, url, html_options = {}). The url parameter can take:
A String like "/users/john-smith"
An Object like #user
An Array like [:admin, user]
A path like admin_user_path(user)
If the url parameter is a String, it just passes that to the href for the link. If the url parameter is an Object, an Array or a path, it passes the value to the url_for method behind the scenes.
url_for will take an Object, determine that the class type is User, and look for a corresponding user_path(#user) route method. With an array, it first takes any symbols and use it to construct the name of the url helper, then it will take any objects and pass it as values. This is how link_to user.full_name, [:admin, user] gets converted to admin_user_path(#user) which finally becomes John Smith
Update
According to this Stack Overflow answer (which links to url_for and polymorphic_url) url_for takes the input and passes it up to the parent method which for some reason adds the current scope. link_to uses url_for by default. polymorphic_path is the method you require if you want to "unscope" it. I tested this concept in a similar situation in my own app and got the same results as #Jwan622.
url_for([:admin, user]) # Does not exist
#=> admin_promotions_users_path
polymorphic_path([:admin, user]) # Exists
#=> admin_users_path
Therefore, you should either use this:
link_to user.full_name, admin_users_path
Or this (if you need to generate the link dynamically):
link_to user.full_name, polymorphic_path([:admin, user])

Forward parameters in the specific order (using link_to helper)

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

Submitting a form with GET method which doesn't match route

I want to filter results by category and I'd like to use the GET method instead of POST. However, I am doing something wrong that I can't figure out: the form's action does not match the defined route, so it triggers a different method.
Here's the form:
<div>
<%= form_tag '/expenses/search', method: 'get' do %>
<%= select_tag 'category_name', options_from_collection_for_select(Category.order(:name), :name, :name) %>
<%= submit_tag 'search' %>
<% end %>
</div>
Sending this form produces an URL like the following:
http://localhost:3000/expenses/search?utf8=%E2%9C%93&category_name=Alcohol&commit=Search
However the route is defined like this:
resources :expenses
get 'expenses/search/:category_name', to: 'gastos#search_by_category'
This means the URL where the form is submitted isn't the one I'm trying to submit it to. It's matched with the one corresponding to the show method, as you can imagine.
How can I submit the form to the matching URL? What is the usual way to deal with this situation?
You didn't set your route properly as it has unrecognized :category_name segment. Your route should be defined like this:
get 'expenses/search', to: 'gastos#search_by_category`
If your route is nested on expenses I recommend to use block function
resources :expenses do
collection do
match 'search', to: 'gastos#search_by_category`, via: :get
end
end
Is a good practice to use rials routes helper, try to avoid put routes with plain text, in your case will be:
<%= form_tag search_expenses_path, method: 'get' do %>
<%= select_tag 'category_name', options_from_collection_for_select(Category.order(:name), :name, :name) %>
<%= submit_tag 'search' %>
<% end %>
Furthermore, don't confuse 'query params' with 'url params'
http//www.host.com/profile/12?type='json'
In this example '12' is a url param and is expresed with :(nameofparam) in routes files but 'type' is a query param that are not expresed on rails routes.
It's supposed to work like that, since it's client-side.
You see, parameters are sent by the browser, that (in general) has no understanding of how your site routing works inside. Submitting a form, in general, requires an URL (to submit params to) and a set of parameters, which in case with GET typically* gets passed as a query string.
The browser will eventually hit the exact route that is specified in form's URL and supply all the form's parameters in a query string appended to the end in usual format:
...?category=stuff
You simply cannot expect the browser to hit a different route (which query string is not part of) with one form just because it has a different value in one of the <input>s.
* I've never actually seen this done differently, but I didn't find a firm requirement of this either.
Do you really want pretty search links that badly?
You could try to circumvent this by placing a "prettifying redirection" – direct search queries to that action, but do not perform search there: instead use the received parameters to construct a route and redirect your user to it.
def search_redirect
redirect_to whatever_search_path(category: params[:category])
end
That would trigger the route helper to build the pretty adress that conforms to the defined routes.
Too hacky?
Well, you could go with submitting a form through JavaScript and alter the parameters and URL request in any way you want. But this is still hacky and I wouldn't do either. Query string in search requests looks perfectly fine to me.

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