URI management and navigation in Ruby on Rails - 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.

Related

Rails: Configure routes to attempt to find records from two classes

This is my current route configuration:
resources :organizations, path: ''
resources :users, path: ''
I want to create a similar experience to what GitHub does. When using GitHub, you can access organization and user profile pages by entering "https://github.com/#{username}"
Now, the routes configuration above leads to the obvious problem that accessing organizations works fine while accessing a user fails because Rails only considers the organizations route and does not attempt to find a user.
Note: I am using friendly id to use usernames in my URL's and also made sure that usernames are unique across both ActiveRecord classes.
How do I do what I want to do?
You can create additional controller like PageOwnerController and pass request to it:
get ':page_owner_nick', to: 'page_owners#show', as: :page_owner
In show action you can manually find desired record by params[:page_owner_nick].
Advice: it looks like you have many a lot of similar logic between users and organizations - take a look on STI. Using STI allow you to write common code easier, but at the same time to separate different logic.

Rails 4.2 routing to ignore part of a URL

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+/ }

Ruby on Rails Routing, Double Nested Slugs

I'm trying to setup the basic routing and URLs of my application. I'm using the FriendlyId gem to have nicer looking URLs.
In my model design an Account has Users, and an Account has Farms. When a User signs in, I want to redirect them to myapp.com/account-name. This page should be an index page of that account's farms, along with some other options. When they click on a farm, I want the page to go to myapp.com/account-name/farm-name.
How do I do this? Is this just totally anti-RESTful to not include /account or /farms in the URL? If it is, then what can I do to have the url be myapp.com/account-name/farms/farm-name?
Right now I have it correctly showing myapp.com/account-name by having
get "/:id", to: "accounts#show", as: 'account'
but I don't think I can extend that to include farms. I think it may be solved with something like
resource :account do
resource :farms
end
But that shows myapp.com/account.account-name when I go to the account, and when I do something like redirect_to account_path(current_user.account) it uses the POST route instead of the GET one.
I'm decently new at Rails, so sorry for misunderstandings. Thanks for your help!
If Farm belongs_to Account (as opposed to HABTM), shallow nesting might be a good route structure.
I've figured out that I can do this by adding one more line in the routes file
get "/:account_slug/:id", to: "farms#show", as: 'account_farm'
Then I can link to a farm in the view with
<%= link_to farm.name, account_farm_path(account_slug: #account.slug, id: farm.slug)
I'm still interested in any answers about if this is good practice or not, or any other recommendations.

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.

Friendly URLs in Github

How has Github managed to get friendly URLs for representing repos of users? For a project called abc by username foo, how do they work around with a URL like: http://github.com/foo/abc. Are they fetching the abc model for the DB from the title in the URL (which sounds unreasonable as they are modifying the titles). How are they transferring the unique ID of the abc repo which they can fetch and show in the view?
The reason I ask is that I am facing a similar problem of creating friendlier URLs to view a resource. MongoDB's object IDs are quite long and make the URL look horrific. Is there a workaround? All the tutorials that demonstrate CRUD (or REST) URLs for a resource always include the object's unique ID(e.g. http://mysite.org/post/1 or http://mysite.org/post/1/edit. Is there a better way to do it?
Not having seen their code, I couldn't tell you exactly how they do it, but if you're using Rails there are at least two Ruby gems that will give you similar results:
Take a look at Slugged and friendly_id
http://github.com/foo/abc is a unique repository identifier (for that repo's master branch). I'd assume that somewhere they have a table that looks like:
repository-id | user-id | project-id
and are just looking up based on user and project rather than repository-id.
You'd need to do some domain-specific mapping between internal and user-friendly ids, but you'd need to make sure that was a 1:1 mapping.
See this rails cast on methods, gems and solutions to common problems you might get while modifying the application to use friendly urls.
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=asciicast
(although Ryan Bates deserves the rep+ for this)
I mocked a structure like this using FriendlyID and Nested Resources.
Essentially, use friendly ID to get the to_param-ish slugs in your routes, then set up nested resources. Using GitHub as an example:
routes.rb
resources :users do
resources :repositories
end
Then in your controller, say, for repositories, you can check the existence of params[:user_id] and use that to determine the user from the route. The reason I check for existence is because I did something like (roughly):
/myrepositories/:repository_id
/:user_id/:repository_id
So my controller does:
def show
#user = params[:user_id] ? User.find(params[:user_id]) : current_user
end
I followed this tutorial here to get started with this same project.
This is called URL rewriting if the web server does it (such as Apache), and routing when it happens in a web application framework (such as Ruby on Rails).
http://www.sinatrarb.com/intro#Routes
http://httpd.apache.org/docs/current/mod/mod_rewrite.html

Resources