searching for a part of the url (without protocol) - ruby-on-rails

In my database i store urls as string, with protocol validation, meaning there has to be a "http://", "https://" or "ftp://" before hostname.
Also, to my controller action POST request is being sent, but just with hostname, no protocol. How can I search database for this hostname?
The easiest solution would be to just construct new string with protocol, but i dont know which one i'm going to need. It might be "https" just as well as "http".
Any ideas?
(NOTE: This is Rails 3 app)
EDIT
It's been pointed out that my question is not clear, so I will try to explain it better now.
In database i have column url. It stores links which begin with "http://", "https://" or "ftp://".
they may look like this:
url:
"http://google.com"
"https://amazon.com"
"ftp://somehostname.com"
My controller gets POST request with hostname, it may be {"domain" => "google.com"}
So now what i need to do is search the database for "google.com" to update it. BUT as you can see, value under "domain" key doesnt store protocol. So i dont know if it is "http://google.com" or "https://google.com", yet i must somehow find it.

request.host
request.host_with_port
request.url
request.host
The just query with .where(:url => current_url)
Not exactly sure what you're asking but these should point you in the right direction (I hope)

From what I understand you are going to get a URL without the protocol in one of your POST params and you want to match it with the ones in your database which HAVE a protocol.
This is what I would do:
Option 1:
If feasible store the protocol and rest of the URL in two separate fields in the database. Easy to compare that way.
Option 2:
Use regular expressions!
Let's say you get params as follows:
{"domain" => "google.com"}
I would then do this to find the record:
(Assuming name of your model is "Record")
domain = params[:domain]
#record = Record.where('name = ? OR name = ? OR name = ?', "https://#{domain}", "http://#{domain}", "ftp://#{domain}" )

Related

Session across domains in Rails 4

I have an issue with wanting to use session across domains (not subdomain). Eg, I have .co.uk, .com.au, and .com all for the same address.
I know for subdomains I can use something like:
SomeApp::Application.config.session_store :cookie_store, key: '_some_app_session', domain => :all, :tld_length => 2
But I would like my solution to work between actually domains to have one set of sessions/cookies.
As your default session store is 'cookie_store'
You could just do it the same way as when you might send an email link with an authentication token. Check to verify that the cookie is correct on example.org and, if it is, redirect them to:
http://example.com?token=
and then check to make sure the token matches the one you have in the DB when they arrive. If the token does match, create the session cookie for the example.com domain and then change the token in the database.
This will successfully transfer from one domain to another while providing persistent login on the new domain (via cookie) and shutting the door behind them by changing the authentication token in the DB.
EDIT
To answer your question below, I don't think you need middleware or anything fancy. You could do a simple before filter in the application controller of example.org, something like:
before_filter :redirect_to_dot_com
...
def redirect_to_dot_com
url = "http://example.com" + request.fullpath
url= destination + (url.include?('?') ? '&' : '?') + "token=#{current_user.token}" if signed_in?
redirect_to url, status: 301
end
That will redirect the user either way, and append the token to the query if the user is signed in on the .org site.
Go to more details on Persisting user sessions when switching to a new domain name (Ruby on Rails)
I wouldn't use the PHP style routings which pass ?php=bad style variables via :get especially if you're already using sessions. And also since then you'd have to parse the original URL and a bunch of other work.
Instead of using session[:edition_id] = 'UK' you can use:
cookies[:edition_id] = { value: 'UK', domain: 'some-app.com', expires: 1.year.from_now }
# or if you want to be google 10.years.from_now
When you use session[:edition_id] = 'UK' the value will be encrypted by rails and stored in the _myapp_session cookie. But in your case that probably doesn't matter much.
If you set the cookie explicitly on the domain you want to read it from, it will work without having to set odd ball variables via get and then trying to interpret them again on redirect.

Prevent an URL from being discovered

Recently I've created a controller, which will do some insert into my database whenever I access the url.
My route config for it :
routes.MapRoute(
"SCRoute",
"SC/{pdate}",
new
{
controller = "SC",
action = "Index",
pdate = DateTime.Today.Date.ToString("yyyyMMdd")
});
My question is if I don't expose this url, will it be detected? Of course since there is no credential log-in, anyone with the link can access the page, but if I can keep it for my self, will it be safe?
There will be no internal links to this controller also. It won't be mentioned anywhere except in my mind and the route config!
but if I can keep it for my self
Its not safe, no matter how you hide it. You can accidently execute this URL or other developer can do that while understanding the code. Lots of things can take place to get it run.
If you want to insert something in DB, why don't you create a script and execute it. It would be a controlled change in any environment.
UPDATE - After comment from user
You can work out a solution on following lines:
Define an action filter.
Check for a unique value in the URL e.g. IP Address (Example) or write an algorithm to generate a hash.
When you want to run the action from anywhere, generate the hash and supply in the URL. The defined filter will verify the hash validity. A request with valid hash will only be served.
Hope this help.

How can I make rails route helpers always use to_param to generate the path, even when I just pass in an ActiveRecord ID?

So, I'm implementing a pretty/SEO-friendly URL scheme for my rails app. I have a model called Artist, and I would like the Rails artist_path helper to always generate the friendly version of the path.
In my routes.rb file, I have the following line:
get 'artists/:id(/:slug)', :to => 'artists#show', :as => 'artist'
If the slug is left out, or is incorrect (it's calculated by the artist name), the controller 301 redirects to the correct URL. However, for SEO reasons, I want to ensure that all links internal to my site have the correct URL to start with.
The Artist model has the two following (very simple) functions to allow this to work:
def slug
name.parameterize
end
def to_param
"#{id}/#{slug}"
end
If I call artist_path with an artist object, this works as intended:
> app.artist_path(Artist.find 1234)
=> "/artists/1234/artist-name"
However, when I use call it with just the ID, it does not seem to use to_param at all:
> app.artist_path(id: 1234)
=> "/artists/1234"
tl;dr: How can I force Rails to always instantiate the object and call to_param on it when artist_path is called, even when only the ID is specified?
As far as I'm aware, the reason why what you're asking won't work is because when you pass in values to the built-in/automatic URL helpers (like an ID, per your example), those values just get used to "fill in the blanks" in the route URL.
If you pass an array, the values from the array will get used in order until the URL is filled in. If you pass a hash, those properties will get replaced into the URL. An object, like your model, will use it's to_param method to fill in the values... etc.
I understand your concern regarding "having knowledge of the limitations of that model," however, this behavior is standard in Rails and I don't believe it would really throw anyone. When you pass in an ID, as you do in your example, you're not telling the URL helper to "lookup a record via the model using this ID," you're simply telling it to "replace ':id' in the URL string with the ID you're providing." I'm fairly certain the built-in URL helpers wouldn't even know how to lookup the record - what model to use, etc. - other than maybe inferring from the route/controller name.
My best suggestion is to always use the instantiated model/record. If you were hoping the URL Helper would look that up for you, then there's no extra overhead as far as querying the database goes. If there's some additional reason you want to avoid instantiating the record yourself, I'd be glad to hear it and possibly provide other suggestions.

Get raw params rather than the "processed into hashes" versions

Rails 3 question.
If i send a request like this PUT http://myapp/posts/123?post[title]=hello
then in my controller i get params = {:id => 123, :post => {:title => "hello"}}
This is fine normally and usually useful for eg Post.create(params[:post])
However, on this occasion i need to get access to the 'raw' form of the params so i can order them pull out the values, dealing with them all as simple strings, ie i want them listed so the param name is "post[title]" and the param value is "hello".
Is there any way i get get these values? I thought there might be a method of request that has the params in their original stringy form but i can't find one.
It had occurred to me to try to convert the hash back into a string with to_param but this seems a but dirty and possibly unecessary.
As a bonus, i'd like it to ignore the :id parameter, literally just taking the part after the ? in the original request. In fact, if i can just get back the original request string, ie "http://myapp/posts/123?post[title]=hello" then that would do: i could split on the ? and take it from there. It just occurred to me that i can probably get it out of a header. In the meantime though, if anyone knows a nicer way then tell me please :)
Grateful for any advice - max
Don't do the parsing by hand, please. Grab the URI from the Rails request:
url = request.url
# Or, depending on the Rails version and stack
url = request.request_uri
# Or even
url = request.scheme + '://' + request.host_with_port + request.fullpath
The return value from request.url seems to depend on your server stack, request.request_uri is supposed to fix that but doesn't seem to exist in Rails 3.1. The third "build it all yourself" approach should produce consistent results everywhere. Sigh.
Then, once you have the URI, use URI.parse and URI.decode_www_form to parse it:
u = URI.parse(url)
q = URI.decode_www_form(u.query)
# if u.query was "a=b&c=d&a=x" then q is
# [["a", "b"], ["c", "d"], ["a", "x"]]
Request#body and Request#uri should help you. You can get the "raw" request data, but not some intermediate form... though it's not that hard to just split at the ampersands and then again at the "=" if you want key-value pairs ;)

Append query string to request.request_uri without knowing if there was a query string

When a user arrives to my site on an iPhone I want to present them with a page with 2 options:
1) Go get our app or
2) Continue on to the requested URL
I do this by checking the user agent in my application controller and rendering a view.
For option 2 to work properly on that view I want the link to preserve the original URL and append a query string parameter fullsite=1. I look for that query string parameter param in a before_filter in my application controller and set a cookie so that the user is not prompted again.
What is the cleanest way to append a query string parameter to a request.request_uri knowing that that request url may or may not have had a query string to start with? I know it is straight forward to check if the request had parameters but I'm wondering if there is a helper to append a parameter cleanly in either case (no params or with existing params) without evaluating things on my own. Seeking the correct "railsy" way to do this.
Probably the best way to do this is to add your flag to the params hash, which will already have all the other information you need to build that link (presuming you catch iPhones and render in a before_filter), and then build your link from the modified params hash:
In your before_filter:
params[:fullsite] = 1
And then in your view:
<%= link_to('Continue to the Full Site', params) %>
This way Rails gets to do all the messy work of escaping and appending your query strings - both :fullsite and whatever the original query string contained.
If you're just using :fullsite as a way to avoid redirecting iPhones through your iPhone portal multiple times, though, it seems like either of these approaches would work better:
Set :fulltext in the session instead, or
Only redirect users if they're on iPhones AND request.referer is something other than your site.
Hope this helps!

Resources