Rails 4.2 routing to ignore part of a URL - ruby-on-rails

My first SO question... Please be gentle :)
I have a specific routing requirement for a Rails 4.2 application but I'm struggling to accomplish it. My client offers it's members a website to sell the company's products and earn a commission on sales (kind of like Amway does)... Basically a glorified affiliate program. The pattern of their URL's is https://www.company.com/membername/products/something-you-can-buy. The requirement is that they keep this pattern in the new application I am building for them.
The membername part could be anything, and this application will not have access to the existing user database... We need rails to ignore the membername part of the url and process routing based on the rest of the URL. So if the URL is https://www.company.com/hephalump/products/hamburger we need routing to ignore the hephalump bit, but still keep it in the URL, and process the routing based on the products/hamburger portion. The client also needs the hephalump bit to stay in there throughout the entire application and we need to be able to capture it as a param at the point of purchase (that's easy enough).
I've been bashing my head against the wall with this for two days with no luck... Any help would be greatly appreciated.

There are many ways to do that. Here's one:
get '/:_member/products/:product_name' => 'products#show'
Substitute the correct controller name prefix for products in products#show and the correct action name for show. In that controller params will have both :_member and :product_name keys, and you can just ignore the :_member key.
You can also add constraints on what pattern can represent a member or a product name, e.g.:
get '/:_member/products/:product_name' => 'products#show',
contraint: { _member: /\w+/ }

Related

Use RESTful routes and POST parameters

I have a website for a college that tracks student information and serves it up to faculty advisors, most of which is confidential. Many features in this site involve passing a student's ID number to the controller. Because student ID numbers are confidential I am curious if I can avoid having the student's ID appear in the URL string as a parameter. Here is what I have investigated so far:
Rather than passing a student's ID via GET I could POST the ID number. This would work fine, but then I am confused on how I could make use of RESTful route helper methods, when the router expects a GET request and I am sending a POST request. Is it possible to customize around this?
A second idea (which I fear might be a bit unelegant) is to store a hash in session data where some arbitrary number served to the user is the key to that students ID number. That arbitrary number appears in the URL string rather than the id number.
The other alternative I can think of is to not use restful resources at all. This is completely doable, but I want to see if there are any other options.
Or is there anything I'm not thinking of (very possible).
Thanks,
I think you may be confusing two different ideas here. Your students may have a unique id number to identify them in the educational system or the school records much like a National identification number. But you do not / should not use that number to identify the records in your rails app.
Instead you would have a normal auto incrementing column in the database to identify students in your application. There is no real reason that the number should be confidential.
The idea behind REST is to use each one of the methods supported GET, POST, PUT, and DELETE in the right scenario.
If the only concern that you have is that the student Id showing in the URL, I suggest that you use the record id (the one that is autoincremented automatically by the database) not the real Id of the student in the requests and add the real ID as an extra field in the table.
Cheers

Ruby on Rails database driven router to support fully customizable urls

I'm planning to port our current cms (written in PHP) to Rails. All parts do well, except for one: routing.
Like most cms systems, the routing in our cms based on a database with pages, which are linked to modules, controllers and actions. On this approach a user can fully customize or specify it's own urls.
I know that Rails (and most (application) frameworks have the approach of defining routes in a file, but I hope this is possible.
The approach our users should have is:
add new page
select type (news, form, product, ...)
select an item (select which form, blog or product should be displayed)
enter a url for that page
Special the last point (4) is important. A user should be able to add form A to /contact-us, and form B to /clients/register-as-new-client e.g.
On a request the router needs to do a database query with the page url, to find out which controller, task and parameters should be dispatched.
Question has been updated, and i don't think this is a valid answer anymore
we have a similar paging system. we use a routing glob. in routes.rb:
get 'pages/*lookup_path', to: 'pages#show', defaults: { format: 'html' }, as: 'page'
Just parse params[:lookup_path] in PagesController to suit your needs
'http://localhost/pages/users/'
params[:lookup_path] #=> users/
'http://localhost/pages/users/23'
params[:lookup_path] #=> users/23
'http://localhost/pages/people/1'
params[:lookup_path] #=> people/1
Although this solution isn't ReSTful, I think this should solve the issue.
Regardless, Rails uses routes in a file. You cannot change this since the framework heralds "convention over configiuration". All I can do is point you in a direction to minimize this.
There is a catchall route in Rails (on RailsCasts, and on StackOverflow) which you can use to direct all routing to one controller action. You may further customize the routing behaviour in that method
You could also make a route like…
:controller/:action => Controller::Action
…as is done in CodeIgniter, but now your methods have to have names like contact-us and register-as-a-new-client.

Referral program - cookies and more (Rails)

I'm building a referral program for my Ruby on Rails app, such that a user can share a link that contains their user ID (app.com/?r=ID). If a referrer ID is present when a visitor lands on app's homepage, the signup form on the homepage contains a hidden field that populates with the referrer's ID. The controller then detects the ID and creates a new referral in a referral table if the referred visitor signs up. It works, and here's that chunk of code:
#referrer = User.find(params[:r]) rescue nil
unless #referrer.nil?
#referral = Referral.new(:referrer_id=>#referrer.id)
end
Pretty simple stuff, but it's pretty easy to break (ex: if visitor navigates away from the homepage, referrer ID is lost). I feel like cookies could be a more robust method, where a cookie containing the referrer's ID is stored on the referred user's computer for x days. This is pretty commonplace, especially with affiliate programs like Groupon, but I have never worked with cookies and have no idea where to start.
Also, is there any good way to mask or change the URLs of the referral system? Instead of having app.com/?r=1842, I would prefer something like app.com/x39f3 <- a randomly generated sequence of numbers associated with a given user, without the ?r= portion.
Any help is greatly appreciated. Thanks!
To answer the cookie question, it's quite easy to set them:
cookies['app-referrer-id'] = params[:r]
And then it's the same format to read them back (but without the assignment). I would suggest putting this code in a before_filter in your application controller. This way, the cookie will be set irrespective of the page on which your visitor first lands on your site.
With regards to changing the structure of the urls to the suggested format, you would need to have the referral codes match a specific pattern, otherwise you are likely to run into routing problems. If, for example, they matched the format of 3 letters followed by three numbers, you could put the following your routes file:
match '/:referrer_id' => 'app#index', :constraints => {:referrer_id => /[a-zA-Z]{3}[0-9]{3}/}
The reference to app#index should be changed to the controller in which you handle referrals and you can access the referrer_id through params[:referrer_id].
Hope this is of some use.
Robin

Thoughts regarding model ids in rails routes and validation

I am new to RoR and started working on a typical 'has_many' association (ie. a user has many friends). I have everything working correctly, but I don't like having the ids exposed in the url. I find that I need to add extra validation in my controller to make sure the ids represent valid associations in case the user manually entered different ids.
Personally I would like to see the ids out of the url and passed via some other means but that is not always possible. Shallow nesting of resources will help reduce the number of ids I need to validate at least.
What is the RoR philosophy on this? I have not seen anything specific to this issue.
Thanks
the URL has parameters if it is a GET url.
Try using POST parameters, which means your url will no longer be cluttered. Note that a malicious user can still send a made-up POST request using curl.
My approach to this is implementing proper authorization. If the user requests information for an object he is not permitted to read, this should be handled by an authorization framework.
With CanCan or Declarative Authorization you can define rules that replace your "manual" (and error-prone) checks in controllers.
I like the IDs being in the URL. That is what REST is about. Getting information for specific Resources, which have to be identified with an ID.
You can use Friendly ID in order to replace the integer ID by a slug (e.g. users/tollbooth instead of users/42).
basically ror routes by default takes id as key to generate urls. If you are not fan of id based urls then you can always override urls by using to_param inside model.
def to_param
# make sure this field is always present & unique
username
end
then by default you will start seeing username instead of id inside urls
How to find object inside controller actions
User.find_by_username(params[:id])
If you dont want to do this manually make use of slug gems like friendly id

URI management and navigation in Ruby on Rails

I'd like to implement a special routing in rails based on the URI (I'm using rails 3.0.4 with Mongoid and devise). Let's say my user logins, once signin I want to redirect him to a private area for example http://www.mysite.com/site1. Many users could belong to site1, many to site2... users of one site are not authorized to see another site. Today the redirection is fine after sign in, but I'm confused on how I should implement siteX (each site has its own data). I have the following route:
match '/:site_name' => 'site#index', :constraints => { :site_name => /'a pattern'/ }
resources :sites do
end
Because I need to stick to this URI format should I nest all my other resources inside :sites? For example if I want to display order 1 of site 2 the URL should look like http://www.mysite.com/site2/order/1. I can't put the resource's name "sites" in the URI as it starts directly with the identifier. Is there another way of doing this, what would be the best pratices? Hope my explanations make sense.
Thanks a lot for all your help!
Ted
I recommend you scrap the idea of "subdirectories". You'll have (not insurmountable) difficulties with link_to and the other helpers.
I would setup subdomains (a la, site1.mysite.com) if that's possible for your situation
Doing url.com/site_name is kind of nuts.
If only one user can belong to a site, take it from the user perspective then and use resource and not resources.
E.g., url.com/orders would be all current_user.orders, since current_user has_one site (or is a member of one site).
If you need site specific navigation, then draw from /site_name for site specific detail that is public in nature. E.g., url.com/site_name/pricing
If you really want to break your site down into /site_name specific routes, then through that into a subdomain. You can even try using sudomain devise to get you started.

Resources