Using rails 2. I want a link to the current page (whatever it is) that keeps all of the params the same but changes the format to 'csv'. (setting the format can be done by having format=csv in the params or by putting .csv at the end of the path). Eg
posts/1
=> posts/1.csv OR posts/1?format=csv
posts?name=jim
=> posts.csv?name=jim OR posts?name=jim&format=csv
I tried this as a hacky attempt
request.url+"&format=csv"
and that works fine if there are params in the current url (case 2 above) but breaks if there aren't (case 1). I could come up with more hacky stuff along these lines, eg testing if the request has params, but i'm thinking there must be a nicer way.
cheers, max
EDIT - btw, it's not guaranteed that the current page could have a named route associated with it, in case that's relevant: we could have got there via the generic "/:controller/:action/:id" route.
<%= link_to "This page in CSV", {:format => :csv } %>
<%= link_to "This page in PDF", {:format => :pdf } %>
<%= link_to "This page in JPEG", {:format => :jpeg } %>
EDIT
Add helper
def current_url(new_params)
url_for :params => params.merge(new_params)
end
then use this
<%= link_to "This page in CSV", current_url(:format => :csv ) %>
EDIT 2
Or improve your hack:
def current_url(new_params)
params.merge!(new_params)
string = params.map{ |k,v| "#{k}=#{v}" }.join("&")
request.uri.split("?")[0] + "?" + string
end
EDIT
IMPORTANT! #floor - your approach above has a serious problem - it directly modifies params, so if you've got anything after a call to this method which uses params (such as will_paginate links for example) then that will get the modified version which you used to build your link. I changed it to call .dup on params and then modify the duplicated object rather than modifying params directly. – #Max Williams
You can use:
link_to "text of link", your_controller_path(format:'csv',params: request.query_parameters)
#floor's answer was great, I found it very useful.
Although the method can be improved by using the to_params method rather than contructing your own, like so:
def current_url(new_params)
params.merge!(new_params)
"#{request.uri}#{params.to_params}"
end
Related
Right now I have a link which routes to a view that lists all of my Users by a given letter, if i click 'A' it displays all my users whose names start with the letter a. How do I do this for users that start with an integer? I assume I'd have to change my params value but I dont know how to do this. this is my code:
<%= link_to 'A', users_charlist_path(:char => "A") %>
right now I have this but it doesnt work:
<%= link_to '#', users_charlist_path(:char => /[0-9]+(\%7C[0-9]+)*/) %>
this is my controller:
def charlist
#a = User.all(:conditions => "goal like '#{params[:char]}%'")
end
I think everything must work. Only few moments.
SELECT * FROM users WHERE email LIKE '7%' ... Works so I think problem with link generation.
never pass parameters like this "#{params}". Because it's not secure. Use :conditions => ['goal like ?", "#{params[:char]}%"]
try your code in console and use pry for debugging.
You could use [0123456789] as wildcard that can be used by any database (source).
<%= link_to '#', users_charlist_path(:char => '[0123456789]' %>
In the controller, as explained by Igor, do not include params directly in the string, that's a security issue
def charlist
#a = User.where('goal like ?', "#{params[:char]}%").to_a
end
I'm new to RoR and I've managed to make a basic search form but keep getting errors when trying to expand the search tags (name).. I have a model with various data (location, website, email, telephone) and was wondering how I can add these to my current search code.
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
static_pages_controller.rb
def home
#ciirs = Ciir.search(params[:search])
end
/home.html.erb
<%= form_tag ciirs_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag " Search Database Records ", :name => nil %>
</p>
<% end %>
When clicking the submit button (no search terms) the url is:
ciirs?utf8=✓&search=
but when modifying the name condition to something like 'website' the url changes to
ciirs?utf8=✓&search=&commit=+Search+Database+Records+ –
Since you mentioned you are new to RoR, I must share the way I learned RoR was reading, using and analyzing one issue at a time. I would suggest you to take a look at following points one at a time and try & learn how RoR treats them and how these fit your question:
How form_tag works?
How text_field_tag works?
Once you have understood form_tag, difference between text_field_tag and f.text_field?
How params objects are created, and it uses names of form controls?
How and when to use GET and/or POST form methods? Inadvertently, what are different types of method and when to use them?
How URL are used in the form_tag and what components are they made of?
Sprinkle a bit of knowledge of Ruby language by learning between Arrays and Hashes? In fact, learn Ruby as much as you can.
Answering your question,
/home.html.erb
<%= form_tag "/static_pages/home", :method => 'post' do %>
<p>
<%= text_field_tag "search[name]", params.has_key?("search") && params[:search].has_key?("name") ? params[:search][:name] : "" %>
<%= submit_tag " Search Database Records " %>
</p>
<% end %>
/models/ciir.rb
def self.search(search)
if search
find(:all, :conditions => ["name LIKE '%?%'", search[:name]])
else
find(:all)
end
end
So I modified your form, and told RoR about search params containing data for name.
params is a Hash (which is a key-value pair) having key named search, which further is a Hash having key named name.
The same principle is followed in the model code. We passed the Hash of key search to the function and in there, used the value of key named name.
I also updated the url in form_tag, to point it to home action of your controller. Assuming that you have added it to your routes.rb file, it usually follows the pattern controller_name/action_name or the function name action_name_controller_name_path or action_name_controller_name_url. Run rake routes command at your root directory to list out all paths in your application.
Also note, I used POST method instead of original GET. You may wish to use GET here, so please change it back.
I hope this works.
I found no error in your code. the url changed to ciirs?utf8=✓&search=&commit=+Search+Database+Records+ is normal. submit_tag generates a button named "commit" defaultly, it will be parsed in the params. I see you add :name => nil , it will fix the problem, the other part of your code needn't to be modified. I copied your code and tested it, it ran smoothly.
I'm trying to build an app that searches twitter for images. Before I get there, I need to jump over the intimidating hurdle of constructing a working search field that feeds a value into a function.
In my index.html.erb file that's controlled by the Pages controller, I have this code:
<%= form_tag root_path ({:controller => "pages", :action => "search", :method => "get", :class => "grabTweets" }) do %>
<%= text_field_tag :tweets, params[:tweets] %>
<% end %>
In my Pages controller I have:
def search
def grabTweets
#tweet = Twitter.search(params[:tweets] + "[pic] "+" path.com/p/", :rpp => 3, :result_type => "recent").map do |status|
#tweet = "#{status.text}" #class = string
#urls = URI::extract(#tweet, "http") #returns an array of strings
end
end
end
Two problems:
My search query isn't being passed into the grabTweets function as proven by the URL after the search is performed:
http://localhost:3000/?action=search&class=grabTweets&method=get (the search query was the word "bridge"
What's wrong with my code that the search query isn't performing correctly.
Should my code that's in the controller be placed in def home or def search, given that I want the search results to show up in the root_path and don't intend to change pages?
Thanks in advance for the help! I'm thoroughly stumped.
I think you need to read a book introducting Rails, as there seem to be many fundamentals you are missing.
You have an action for the page you are on (which you seem to call 'home') and an action for the search results. Your form needs to call the url for the search action. That would look like this:
<%= form_tag({:controller => "pages", :action => "search"}, {:method => "get", :class => "grabTweets"}) do %>
...
(See the API for more details on the form_tag method)
In that state, it will call the search action (which should not have another method called grabTweets nested inside it - that makes no sense) which will then render search.html.erb (presumably a page of search results).
In your routes file, you need a route for both home and search.
If you want the page to update without refreshing the page, then you need to use :remote => true on the form and handle the response using AJAX.
If you want the two pages to be the same, but with one containing results, then either move the search functionality into the home action and only call it if params[:tweets] is populated, or just have both actions render the same template.
I would recommend reading through the Rendering Guide and the Controllers Guide to learn more.
I have a shop application and another site thats for a special promotion. I've used Active Resource to import products from the shop in to the promo site and added a shopping cart to add the products. However, to actually order the products I need to send the items to the shop application, creating a new cart there to finish the order.
I've made a demo 'RESTful' application to practice using xml to send data back and forth, so I'm trying to use the principles of REST for the real app. However, I need to send the products to a non-RESTful controller. Just to give you an idea of the Cart controller in the shop, here are its actions:
def index…
def add…
def checkout…
def update…
def remove…
def empty…
def apply_discount…
def remove_discount…
def apply_credits…
def remove_credits…
def stock_check…
# My action to accept items from carts in other apps
def cart_import…
And in routes.rb, the only route relating to the cart is currently
map.cart 'cart/:action/:id', :controller => 'shop/cart'
I've inherited the shop application from a previous developer, so I'd probably try to make it more RESTful if I was to make it from scratch.
Anyway, I'm pretty confident that I can get the cart to respond to XML, even without being defined with map.resources. My problem is how to send a hash of the cart items and quantities from the promo app.
To group the cart items and quantities I've collected the item's product id and quantity in to a hash:
<% #items = Hash.new %>
<% #cart.items.collect {|i| #items[i.product_id] = i.quantity} %>
Which when inspected gives the following output:
<%= Rails.logger.info #items.inspect %>
{1144=>2, 1143=>1}
So I figured to send them to the shop I could pass them in a posted link_to:
<%= link_to 'Export Cart', "http://shop.example.com/cart/cart_import", :items => #items, :method => :post %>
That doesn't seem to do anything, whereas omitting the first field appends the items to the URL in a format that looks sensible, but appears as a relative link on the promo application:
<%= link_to "http://shop.example.com/cart/cart_import", :items => #items, :method => :post %>
http://promo.example.com/cart?items[1143]=1&items[1144]=2&method=post
I'm sure the clue is in that the #items object needs to be passed in with the url, but since I can't use a named route I don't really know how to get it in there so that it is posted in the correct format.
Thanks for the help,
Gareth
the way you are passing in the parameters for the link_to method is assuming that :items is one of the link_to options, not one of the url options. this is an order of precedence issue and if you wrap your url inside parens then you can use the options available for the url_for method on your url, to build the path: http://apidock.com/rails/ActionView/Helpers/UrlHelper/url_for
You can't use a link to generate a POST request. It is turning to a GET request. Better use javascript to generate a post request on click of a button or some other event.
In the end I made a helper:
def hash_to_params(items)
result = ""
i = 0
items.each do |item|
i > 0 ? result += "&" : result += ""
result += "items[#{item[0]}]=#{item[1]}"
i += 1
end
return result
end
Then for the link I called the helper:
<%= link_to "export", "http://shop.example.com/cart/cart_import?#{hash_to_params(#items)}", :method => :post %>
Pretty ugly way of doing it, but I really can't think of anything better?
Cheers,
Gareth
I have problem with my application.
I have table report, there are 2 column , user_id and comment_id
I created link on article comment view
<%= link_to "[ ! ]", report_comment_url(comment) %>
class CommentsController < ApplicationController
def report
#comment = Comment.find(params[:id])
#comment = CommentReport.new(params[:comment_report, :comment_id])
if #comment_report.save
redirect_to :back
end
redirect_to :back
end
end
but it was error
ActionController::MethodNotAllowed
Only post requests are allowed.
Do you have any suggestion how to post current_user id and comment_id to report table ?
Given what I assume you're trying to accomplish, I'd suggest you use link_to_remote.
params[:comment_report] is nil because there's no reference to that in your link_to statement. Since you mention in the comment that your view is:
<%= link_to "[ ! ]", report_comment_url(comment), :comment_id => comment.id, :user_id => comment.user_id %>
Then you need this in your controller:
#comment_report = CommentReport.new(:user_id => params[:user_id], :comment_id => params[:comment_id])
But I agree with NSD that link_to_remote would work better for what you want to accomplish (which is create a new record and return the user to the page). You would also eliminate the need for your #comment = Comment.find(params[:id]) statement.
Here's what's going on:
Using Restful routes, you've set up report as a post operation. Which seems reasonable because report is performing the create action.
Unfortunately link_to doesn't know or even care about that. Links in general only perform get requests. Forms produce post requests, but they seem unnecessary in this case.
You have four options.
Make the [ ! ] link a button on a form submitting to report.
Break RESTful guidelines and redefine report receive get requests.
Make this a link_to_remote call. N.B. This relies on javascript and will not work at all if Javascript is disabled.
Add the method options to the link_to call. N.B. This also relies on javascript and will fall back to a get request if javascript is disabled.
<%= link_to "[ ! ]", report_comment_url(comment), :method => :post %>
However none of these solutions will solve all your problems. There are a couple of bugs with your posted code that you may not have realized yet.
First:
#comment = CommentReport.new(params[:comment_report, :comment_id])
is bad syntax and will fail. There are a number of ways to fix this, the preferred method is to to roll :comment_id into the params[:comment_report] hash to fix this.
Ie pass the params as:
params = {
:id => 4, # done by report_comment_url
:comment_report => {
:attribute1 => value1,
...
:comment_id => 4
}
}
Now you can use
#comment = CommentReport.new(params[:comment_report])
for the desired effect.
Second:
report_comment_url does not pass along the additional parameters, so your controller will try to save an empty record. Adding the comment_report to the arguments of report_comment_url will fix this problem.
This will perform a remote call requesting the report action in the comments controller, with the parameter hash required to fix the other problem.
<%= link_to_remote "[ ! ]", report_comment_url(comment,
:comment_report => {:attribute1 => value1, ..., :comment_id => comment.id}),
:method => :post %>