I'm trying to pass an audio URL as a parameter in Ruby on Rails, and googling "how to pass a url in a url" has proved to be problematic. The problem is that I can only get the url to return minus a crucial forward slash.
My route looks like:
get 'my_page/:title/*url', to: 'my_page', action: 'show'
The variable is defined in the controller like so:
#url=params[:url]
So the request would look like:
www.my_app.com/my_page/im_a_title/http://im_a_url.mp3
The url variable, however, ultimately results missing a slash after the prefix:
http:/im_a_url.mp3 <--notice the missing forward slash
Of note, the construction of the urls varies enough that it would be cumbersome to construct them. (Some begin with http and some https, for instance.) How do I preserve the syntax of my url? Or is there a better way to pass this parameter all together?
Why don't you pass the url as a required parameter. That way you can use the built-in to_query.
get 'files/:title' => 'files#show'
and in files controller
class FilesController < ApplicationController
def show
url = params.fetch(:url) # throws error if no url
end
end
You can encode the url and unencode like so:
{ url: 'http://im_a_url.mp3' }.to_query
# => "url=http%3A%2F%2Fim_a_url.mp3"
Rack::Utils.parse_query "url=http%3A%2F%2Fim_a_url.mp3"
# => {"url"=>"http://im_a_url.mp3"}
You should url encode the parameters before passing them in
Rails 4
match 'my_page/:title/:url', to: 'my_page#show' , constraints: { url: /[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}/}, via: :get, :format => false
constraints will match only a regex for a url.
format => false will ignore the dot part of the url
Related
Is there a way in Rails to extract the HTTP verb(s) associated with a route? For example, given a route like this:
match 'users', to: 'users#show', via: [:get, :post]
Can I achieve something like this?
users_path.respond_to?(:get) (obviously #respond_to is not the right method)
The closest I've managed to come is by doing the following, but it doesn't really seem satisfactory.
Rails.application.routes.routes.named_routes["users"].constraints[:request_method] # => /^GET$/
For context, I have an action that sets a cookie and then does a redirect_to :back, but this action is available globally across the entire site (it's in the footer). So, if a user happens to be in a flow, and one of those routes only accepts POSTs, the redirect fails because the request issued is a GET.
The request object is available to your controller. The following methods are available to determine the type of HTTP request:
if request.get?
# request is a GET request
if request.post?
# request is a POST request
There are similar methods for other HTTP request verbs, including PUT and DELETE.
UPDATE:
Per the update to the question, the following code can be implemented within your controller to yield the constrained verbs on any named route as a pipe-delimited string:
Rails.application.routes.named_routes["users"].verb
#=> "GET|POST"
Accordingly, you can split the string to retrieve an array of each of the HTTP methods specified in the route's constraints:
methods_string = Rails.application.routes.named_routes["users"].verb
#=> "GET|POST"
methods_array = methods_string.split('|')
#=> ["GET", "POST"]
methods_array[0]
#=> "GET"
methods_array[1]
#=> "POST"
for someone looking with it in future you can use
env["REQUEST_METHOD"]
to get HTTP verb of specific action
So I need to hit a url like mydomain.com/proxies/www.msn.com in order to fulfill some ajax requests for an API
In my route I have
get "/proxies/:url" => "proxies#get"
and I in the controller I have
url_contents = Net::HTTP.get(URI.parse(params[:url]))
which if i put /proxies/www i get
undefined method `request_uri' for #<URI::Generic:0x3f89508 URL:www>
if i put /proxies/www.msn.com
I get
No route matches [GET] "/proxies/www.msn.com"
You have two separate problems here:
You're trying to treat a URL without a scheme as an HTTP URL.
Your /proxies route won't match :urls with dots and slashes the way you're expecting it to.
For the first one, you'll have to add the schema manually:
url = 'http://' + params[:url]
content = Net::HTTP.get(URI.parse(url))
For the second one, you can use a splat-route to deal with embedded slashes and :format => false to keep Rails from trying to treat .com, for example, as a format:
get '/proxies/*url' => 'proxies#get', :format => false
If you use :url, Rails will see embedded slashes as component separators and that's probably not what you want. Without the the :format => false, Rails will try to interpret .X (for any X) as a format (just like .html, .json, ...) rather than as part of the URL.
This is applicable for rails-2
The problem is with the dot(.) I guess. Ive tried something like below and it worked.
#routes.rb
map.get_proxy 'proxies/:url', :controller => "Proxies", :action => "get", :requirements => { :url => /.*/ }
#view file
#Here dot(.) are needed to replace with its encoded string %2E
<%= link_to 'Get The Site', get_proxy_url('www.msncom') %>
#Proxies Controller
#After receiving the url the %2E need to conovert to dot(.) again.
url_contents = Net::HTTP.get(URI.parse('http://'+params[:url]))
modified as stated by #mu.
match '/proxies/:url' => 'proxies#get', :as => :proxies_get
I'm creating an entry form that I want to only be accessible when three url params are in place: example.com/entries/new/2011/01/27 If someone tries to access any other url (i.e. example.com/entries/new or example.com/entries/new/2011/) I want Rails to set an :alert and bounce the user back to the index page.
Currently, I only have this code in my routes.rb match '/entries/new/:year/:month/:day' => 'entries#new'. What do I need to do to control the redirection if the proper params aren't in the URL? Would I check for each param in the controller and then perform a redirect_to, or is this something I can do from the routes.rb file exclusively? If it's the former, is there an easier way to check that all three params exist other than:
if params[:year].nil && params[:month].nil && params[:day].nil redirect_to ...
This route requires the presence of all three parameters:
match '/entries/new/:year/:month/:day' => 'entries#new'
With only that route, GET /entries/new will result in:
No route matches "/entries/new"
You can redirect from within routes.rb like this:
match '/entries' => 'entries#index'
match '/entries/new/:year/:month/:day' => 'entries#new'
match "/entries/new/(*other)" => redirect('/entries')
The second line matches paths where all three parameters are present. The third line matches all other cases of /entries/new using "route globbing", and does the redirect. Requests matched by the third line will not hit EntriesController#new.
Note: you may not need the first line if you've already defined a route to EntriesController#index -- but watch out for resources :entries, which will redefine index and new.
More info can be found in the guide Rails Routing From the Outside In. When using date parameters, constraints are a good idea (Section 4.2)
Sorry about that confusing title :) I have a resource, ComatosePage (used in the comatose cms plugin), which has a table called comatose_pages which has a field 'full_path' which has values like this: "en/home/logged-in/subscriber/school-top" to set up a route so that i can use this full_path field to load a ComatosePage from the db, instead of the standard id field, so that this url:
/comatose_admin/en/home/logged-in/subscriber/school-top
loads the comatose_admin controller's edit action, passing everything after comatose_admin/ through as a parameter, ie generates this for rails:
Parameters: {:controller => "comatose_admin", :action => "edit", :full_path => "en/home/logged-in/subscriber/school-top"}
The complication lies in the fact that the string is broken up with forward slashes, which is going to confuse routes, i think. Can i set up routes to take everything after "comatose_admin/" and put it into a single parameter?
You can use wildcards in your routes that will match forward slashes. Try something like this:
"/comatose_admin/*full_path"
Then params[:full_path] should contain the rest of the request path.
See Route Globbing
What is the simplest way to identify and separate GET and POST parameters from a controller in Ruby on Rails, which will be equivalent to $_GET and $_POST variables in PHP?
You can use the request.get? and request.post? methods to distinguish between HTTP Gets and Posts.
See http://api.rubyonrails.org/classes/ActionDispatch/Request.html
I don't know of any convenience methods in Rails for this, but you can access the querystring directly to parse out parameters that are set there. Something like the following:
request.query_string.split(/&/).inject({}) do |hash, setting|
key, val = setting.split(/=/)
hash[key.to_sym] = val
hash
end
You can do it using:
request.POST
and
request.GET
There are three very-lightly-documented hash accessors on the request object for this:
request.query_parameters - sent as part of the query string, i.e. after a ?
request.path_parameters - decoded from the URL via routing, i.e. controller, action, id
request.request_parameters - All params, including above as well as any sent as part of the POST body
You can use Hash#reject to get to the POST-only params as needed.
Source: http://guides.rubyonrails.org/v2.3.8/action_controller_overview.html section 9.1.1
I looked in an old Rails 1.2.6 app and these accessors existed back then as well.
There is a difference between GET and POST params. A POST HTTP request can still have GET params.
GET parameters are URL query parameters.
POST parameters are parameters in the body of the HTTP request.
you can access these separately from the request.GET and request.POST hashes.
request.get? will return boolean true if it is GET method,
request.post? will return boolean true if it is POST method,
If you want to check the type of request in order to prevent doing anything when the wrong method is used, be aware that you can also specify it in your routes.rb file:
map.connect '/posts/:post_id', :controller => 'posts', :action => 'update', :conditions => {:method => :post}
or
map.resources :posts, :conditions => {:method => :post}
Your PostsController's update method will now only be called when you effectively had a post. Check out the doc for resources.
I think what you want to do isn't very "Rails", if you know what I mean. Your GET requests should be idempotent - you should be able to issue the same GET request many times and get the same result each time.
You don't need to know that level of detail in the controller. Your routes and forms will cause appropriate items to be added to the params hash. Then in the controller you just access say params[:foo] to get the foo parameter and do whatever you need to with it.
The mapping between GET and POST (and PUT and DELETE) and controller actions is set up in config/routes.rb in most modern Rails code.
I think what Jesse Reiss is talking about is a situation where in your routes.rb file you have
post 'ctrllr/:a/:b' => 'ctrllr#an_action'
and you POST to "/ctrllr/foo/bar?a=not_foo" POST values {'a' => 'still_not_foo'}, you will have three different values of 'a': 'foo', 'not_foo', and 'still_not_foo'
'params' in the controller will have 'a' set to 'foo'. To find 'a' set to 'not_foo' and 'still_not_foo', you need to examine request.GET and request.POST
I wrote a gem which distinguishes between these different key=>value pairs at https://github.com/pdxrod/routesfordummies.
if request.query_parameters().to_a.empty?