Setting dynamic link path with url parameters in rails - ruby-on-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)

Related

What Ruby construct does the link_to method in Rails use?

Say I have this route:
match '/somepage' => "home#somepage"
I can then do this on a different page to link to "somepage":
<%= link_to "Some Page", somepage_path %>
I'm new to both Ruby and Rails, and I'm struggling to understand how exactly the "somepage_path" part works. It's not a string, it's not a symbol, is it a method call? If so, where does that method exist? Seems like I'm missing something obvious...
On initialization all paths are generated according to the routes.rb definitions.
If you want to customize the routes names you can use
match '/somepage' => "home#somepage", :as => "foobar"
Later used as
<%= link_to "Some Page", foobar_path %>
Hope that clears some stuff up about custom routing :)
Link magic is all handled by ActionDispatch::URL::UrlFor, see ActionDispatch::URL::UrlFor

Problem Sending Value to New Action in Rails 3

I am currently trying to define my first new action in Rails 3, despite various problems I think things are almost done now. However, I as a final hurdle I am struggling to send the correct parameter value to my function...
My function is defined in items_controller:
def clickcountplusone
clickeditem = Item.find(params[:id])
redirect_to clickeditem.externalurl if clickeditem.update_attribute(:click_count, clickeditem.click_count + 1)
end
routes.rb contains:
match '/items/clickcountplusone', :to => 'items#clickcountplusone'
and the view contains:
<%= link_to image_tag( item.picture.to_s + ".gif", send("items_clickcountplusone_path", item.item_name)%>
The view page itself loads correctly (the one with the link on it), but when I click on the link I get an error:
Couldn't find Item with ID=clickcountplusone
{"id"=>"clickcountplusone",
"format"=>"whatever the name is"}
and rather than going to the external page, my browser tries to load:
http://localhost:3000/items/clickcountplusone.whatever the name is
Can anyone tell me how I should be calling the function so that the ID is the item_name and the external URL is visited rather than an incorrect one on my site?
Thanks in advance
It seems like this would be a normal route, instead of a RESTful route (this is fine). There are some places you have to change.
First, in your controller's action, you used params[:id] which is not set actually.
In this particular case, I would suggest you use params[:item_name] instead of id because you are really sending the item_name.
def clickcountplusone
clickeditem = Item.find_by_item_name(params[:item_name])
redirect_to clickeditem.externalurl if clickeditem.update_attribute(:click_count, clickeditem.click_count + 1)
end
Item.find could only be used if the parameter is one of the actual id / :all / :first / :last.
You are finding by the item_name, so you should use Item.find_by_item_name instead.
Second, you have to update you route too (or else you would need something like /you_path..?item_name=blahblahblah which is fine too if you don't mind)
get 'items/:item_name' => 'items#clickcountplusone', :as => :items_clickcountplusone
Third, you view. IMO, most of the time if you are using send but not writing library / really back end code, you probably misusing it.
<%= link_to image_tag("#{item.picture.to_s}.gif"), items_clickcountplusone_path(:item_name => item.item_name) %>
You don't have any variable in your match statement. Try something like
match '/items/clickcountplusone/:id', :to => 'items#clickcountplusone'
and
<%= link_to image_tag(item.picture.to_s + ".gif", items_clickcountplusone_path(:id => item.item_name))%>

Rails: How do I add an additional parameter to resource-based link_to call?

I have a resource defined in routes.rb like so:
map.resources :users
I like using the cleanest link_to option, which would be:
link_to #user
I'd like to add an additional parameter to this call, though: "view=local"
If I were using the user_path, I'd do this:
link_to user_path(#user, { :view => 'local' })
Is there a way to get the same result without including the user_path function explicitly? Ideally, I'd do something like:
link_to #user, { :view => 'local' }
but that doesn't seem to work.
No, you can't. The only real control you have is the ability to add more params on the link tag. link_to has a third parameter that would let you add things like a title attribute on the HTML tag, but it's not going to modify the href value.
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M001597
Go ahead and use the user_path helper. As with most things in Rails, if you want to do the default action, it's going to be simple. You want to do something more complex, so you have to do more work :)

Using named routes with parameters and form_tag

I'm trying to create a simple search form in Rails, but I think I'm missing something.
I have a named route for search:
map.search ":first_name/:last_name", :controller => "home", :action => "search"
I'm trying to use that in my search form:
<% form_tag(search_path, :method => 'get') do %>
<%= text_field_tag(:first_name) %>
<%= text_field_tag(:last_name) %>
<%= submit_tag("Search") %>
<% end %>
But when I load up the search form I get an ActionController::RoutingError:
search_url failed to generate from {:action=>"search", :controller=>"home"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: [:first_name, :last_name] - are they all satisfied?
What am I missing? I thought the fields defined in my form would be automatically linked up with my route parameters. :-/
Update:
I understand that search_path is generated before the form is displayed now, so it can't be updated. Obvious in hindsight!
I changed my routes:
map.search 'search', :controller => "home", :action => "search"
map.name ':first_name/:last_name', :controller => "home", :action => "name"
And now the search action just does:
def search
redirect_to name_path(params)
end
It all works a treat! The main goal here was getting that URL from the name named route as result of doing a search. Thanks guys!
form_for generates form and it has to have specified all parameters that are needed to create search_path, so it should look like:
<% form_tag(search_path, :firstname => 'some_text', :lastname => 'some_text', :method => 'get') do %>
or at least something like this. HTML tag form has parameter action='/some/url' and that's why you have to specify all parameters for search_path. But the above example won't work as you expected.
So what you can do?
Create empty form that has action='/' and with js replace it with content of your input text fields before submitting.
Create another route, on example /search that recives parameters from submit and then redirects to correct path.
Probably there is also some better ways to do it ;)
First, search_path is actually a method, which takes a hash of options. It is this method which should receive :first_name and :last_name.
Second, a browser can only submit form parameters as the body of a POST request, or as query string parameters (for any kind of request method). So there's unfortunately no way a browser's native submit function can generate that kind of URL.
Another way of thinking of it: What you're doing here is filling the form tag's action attribute with an URL. Rails needs a complete URL as you're building the form. So all parameters in your route need to be specified when the form helper is called, rather than at the next POST request.
So unfortunately, what you're trying to do is not possible in a normal Rails application.
(If you really want to, you might be able to pull it off by writing your own form helpers and a bit of Javascript to replace the browser's native submit function. The Javascript would then construct that URL based on the form fields. I'd argue against it, though.)

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