What is the best way of writing this conditionality in rails? - ruby-on-rails

In My rails application, the users will enter a URL Which contains country name, like below.
example :
localhost:3000/usa
localhost:3000/uk
localhost:3000/canada
And my current logic in the Application is like this.
if ["usa","canada","uk"].include? (request.url.split("/").last)
# some logic
end
Is there any better way of writing the above condition?

I'd prefer define it in config/routes.rb
For example:
get "/countries/:name", to: "countries#show"
As a result you'll have params[:name] in the controller equal to country name from the route.
But if you have the exact list of countries, maybe you'll want to define a separate route for each of these.
get "/usa", to: "countries#usa"
get "/uk", to: "countries#uk"
get "/canada", to: "countries#canada"

Related

How to get an organized search URL result with slashes orders (/)?

I want a search section on the "index" from books_controller with some filter options from different authors, categories and other attributes. For example, I can search for a category "romance" and max pages = 200. The problem is that I'm getting this (with pg_search gem)
http://localhost:3000/books?utf8=%E2%9C%93&query%5Btitle%5D=et&button=
but I want this:
http://localhost:3000/books/[category_name]/[author]/[max_pages]/[other_options]
In order that if I want to disable the "max_pages" from the same form, I will get this clean url:
http://localhost:3000/books/[category_name]/[author]/[other_options]
It'll work like a block that I can add and remove.
What is the method I should use to get it?
Obs: this website, for example, has this kind of behavior on the url.
Thank you all.
You can make a route for your desired format and order. Path parameters are included in the params passed to the controller like URL parameters.
get "books/:category_name/:author/:max_pages/:other_options", to: "books#search"
class BooksController < ApplicationController
def search
params[:category_name] # etc.
end
end
If other options is anything including slashes, you can use globbing.
get "books/:category_name/:author/:max_pages/*other"
"/books/history/farias/100/example/other"
params[:other]# "example/other"
So that gets you the basic form, now for the other you showed it could just be another path since the parameter count changed.
get "books/:category_name/:author/*other_options", to: "books#search"
params[:max_pages] # nil
If you have multiple paths with the same number of parameters, you can add constraints to separate them.
get "books/:category_name/:author/:max_pages/*other", constraints: {max_pages: /\d+/}
get "books/:category_name/:author/*other"
The Rails guide has some furth information, from "Segment Contraints" and "Advanced Constraints": http://guides.rubyonrails.org/routing.html#segment-constraints
If the format you have in mind does not reasonably fit into the provided routing, you could also just glob the entire URL and parse it however you wish.
get "books/*search"
search_components = params[:search].split "/"
#...decide what you want each component to mean to build a query
Remember that Rails matches the first possible route, so you need to put your more specific ones (e.g. with :max_pages and a constraint) first else it might fall through (e.g. and match the *other).

Allowing users to create specific routes in rails app

In my Rails app users have possibility to enter their own domain for their page if they want. The value of the domain name saving in the database.
For now routes are look something like this: /user/sites/3.
So, for example, user entered domain name as: "mystuff". And previous route should change to this: /mystuff
How can implement this?
Thank you.
here's an example from rails guides on how your route should look like:
get ':username', to: 'users#show', as: :user
this produces route such as /bob refering to users controller show action
what do you mean domain? you mean sub-domain or sub-url?
If you want to create sub-url for MyStuff (eg. http://www.domain.com/mystuff)
1) you need to create slug field to parameterized the text which you want to be sub-url.(or) can also use parameterized method. (eg. My Stuff => my-stuff)
2) create a route
get ":site_slug", to: 'home#site'

Rails rename model name in url dynamically

In Rails, I have a model named item. Each item belongs_to category (another model), which has an attribute called name.
When seeking any item, I see the url as /item/:id
instead, I would like the url to show up as /'item.category.name'/:id
e.g. if the item belongs to category whose name is "footwear", then, I would like to see the url as /footwear/:id. And if there is another item that belongs to category whose name is "clothing", then I would like to see the URL as /clothing/:id
Is this possible?
If you setup a route like
# config/routes.rb
RouteTest::Application.routes.draw do
get ':category_name(/:id)', to: 'items#show', constraints: {id: /\d+/}
end
It will map to the show action in your ItemsController, and in there, you will have access to params[:category_name] and params[:id]. With this information, you should be able to get the data you want and render it.
Note that this route however will likely have the undesirable effect of masking any routes that follow. You could use rails advanced route constraints to further narrow down 'which values would be considered valid category_names' but this wouldn't be a very scalable or manageable approach.
For example, you could do something like
RouteTest::Application.routes.draw do
get ':brand_name(/:id)', to: 'items#show', constraints: lambda { |request| BrandList.include?(request.params[:brand_name]) }
# etc. ...
get ':category_name(/:id)', to: 'items#show'
end
but this only really works well when the BrandList is a finite list that you could setup during application initialization.
A better, more scalable approach might be to design your URLs like
/brand/adidas
/brand/teva
/shoes/1
/shoes/2
/jackets/45
IOW, prefix known namespaces like brand with an appropriate human friendly URL prefix and use category based route as a catch-all at the bottom.
Hope this helps.

Rails Controller - getting the index action to display only certain records

By default the rails controller will load all associated objects in the index action. What I would like to do is display only certain objects.
For example
I have a model called Car(id, make, model, year). I want list only particular makes in the index, depending on a parameter.
There are a few ways to do this, I'm just not sure which is best.
I could:
pass a parameter to the link:
cars_path(make: 'Acura')
and would give me /cars/?make=Acura
set up routes: (this seems to get messy)
match "cars/:make" => "cars#index", constraints: {make: /[A-z]{1,20}/}
or I could make a separate controller action for this
Any suggestion about what is the most "rails-y" way to do this? RoR 3.1
Usually, when we are talking of filtering data, I prefer to keep the same index action and filtering parameters via plain old GET vars (no extra route definitions) url?key=val&key-val.
This has a number of benefits among them:
url is bookmark-able
no session tinkering
I can reuse the filtering params and pass them to pagination links and such to have the filter follow the user while search is in order
I prefer not to make extra routes as the complexity of the filter can easily go too high. If the filter params are few and you are sure of what you are doing, you may define extra nice routes url/param/param but I find that those cases are few to none.
If you just want to display the cars of one make, the best url imo would be: /makes/1-Acura/cars. So you would just get the cars of this make in the cars controller.
Do you have a table for makes or is it just a string in your car table? I think you should have one.
resources :makes do
resources :cars
end
With these routes, you would have to test if there is a params[:make_id] in the index action of the cars controller, and if it's the case you would get the cars like that:
#cars = Make.find(params[:make_id]).cars
Or you could set up your routes like that
resources :makes do
scope :module => "make_scope" do
resources :cars
end
end
This way, you can have your controllers setup like that:
controllers
- cars_controller.rb
- make_scope (folder)
- cars_controller.rb
The path make_cars_path(#make) would hit the index action in the make_scope/cars_controller, so you would not have to worry about the presence of a params[:make_id], you would just know you're working with the cars of a make.
Otherwise, the get params are fine. I don't think it's bad to define a new route to get prettier urls though, depending on the complexity of your filters.

How to create referral link like launchrock in ruby on rails?

I want to create referral links like.
www.abc.com/1234
www.abc.com/4345
Where number are the referral codes which will be unique for every user. I am sure this can be done in ruby on rails with some routes configuration. Means where the request will be routed. Which controller? which action? How to get value of unique code.
ps: launchrock is using referral links like this.
You can use this structure with route matching but you would need to have the referral codes match a specific pattern. 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].
Certainly have a look at the link referenced in Markus' answer for suggestions on how to generate the tokens.
I have a link in my bookmarks with regard to token generation: http://blog.logeek.fr/2009/7/2/creating-small-unique-tokens-in-ruby
In your application you will need to store the individual tokens in the user table. Controller and action are up to you and for the routes you could go with something like www.abc.com/referral?123456.
routes.rb
match "/referral/:ref" => "controller#action"
access in controller with:
params[:ref]

Resources