rails mongoid url shortner - ruby-on-rails

I've started creating a model based solution for creating short URLs, but I'm wondering if it wouldn't be better to do it in it's own collection (using mongoid) build an index for the tokens between models then search? Or if there's a gem that exists instead of rolling my own solution.
Right now i'm using Mongoid::Token which generates a unique token (ie cUaIxBu) for the particular collection and then using an additional letter (->(c)UaIxBu) to figure how which controller to route the particular request to.
Any ideas or pointers?
In this example alternatedoma.in/cUaIxBu would point to realdomain.com/cities/1234
routes
get '/:id' => 'home#tiny_url', :constraints => { :domain => 'alternatedoma.in' }
controller
def tiny_url
case params[:id].slice!(0)
when 'f'
#article = Article.find_by_token(params[:id])
redirect_to feature_url(#article)
when 'c'
#city = City.find_by_token(params[:id])
redirect_to city_url(#city)
when 'p'
#place = Place.find_by_token(params[:id])
redirect_to feature_url(#place)
end
end

We're employing an almost identical system in an application that I'm currently working on - and it seems to be working out okay (so far!). The only thing I could think of, is that you could boil down your LoC, as well as easily adding support for other models (if required) in the future:
supported_models = {:a => Article, :c => City, :p => Place}
prefix = params[:id].slice!(0).to_sym
if supported_models.has_key?(prefix)
#obj = supported_models[prefix].find_by_token(params[:id])
redirect_to send(:"#{supported_models[prefix].name.underscore}_url", #obj)
end
Obviously, this would require your routing helpers to follow the the same naming as your models. I.e: Article > article_url, City > city_url, etc.

Related

Modify routes in existing Rails Application

I try to modify existing routes in rails application to make it more readable for human and for google.
Existing route example: http://localhost:3000/search_adv?locale=de&q[home_type_eq]=1
To: http://localhost:3000/bowling?locale=de
How to create these routes without 'big' code modifying?
Where home_type=1 parameter corresponds to bowling.
home_type=2 to restaurant and so on.
Altogether six such parameters.
In routes.rb: get 'search_adv' => 'pages#search_adv'
In controller:
def search_adv
if params[:search_adv].present? && params[:search_adv].strip != ""
session[:loc_search] = params[:search_adv]
end
if session[:loc_search] && session[:loc_search] != ""
#rooms_address = Room.where(active: true).paginate(page: params[:page], per_page: 10).near(session[:loc_search], 1000, order: 'distance')
else
#rooms_address = Room.where(active: true).paginate(page: params[:page], per_page: 10)
end
Your question shows how you are thinking about rails which is not the correct way and I would also suggest what Tom Lord suggested but there is a way to do what you want to do, although it would require major refactoring of your code base and not worth it:
You can add a M, V and C each for the home_types (restaurant, bowling etc.) and then redirect from search_adv method to that controller route based on params.
For example:
You hit http://localhost:3000/search_adv?locale=de&q[home_type_eq]=1 and then in search_adv you can
if params[the exact params containing your value] == 1
redirect_to bowlings_path(locale: 'de')
end
The user will not feel it as the redirection will happen on the back-end but the route later will look like:
http://localhost:3000/bowlings?locale=de

Rails: finding database records

In order to improve my understanding of Rails, I'm converting a Sinatra app that uses data_mapper.
I'm trying to find the best replacements for data mappers 'first' method that searches database and returns first instance of the record sought.
Can anyone comment if this is done right, or if there's a better solution?
Situation #1
Sinatra
url = Url.first(:original => original)
Rails (both of these ok?)
url = Url.find_by_original(original) #this find_by_original
url = Url.where(:first_name => 'original')
situation #2
Sinatra
raise 'Someone has already taken this custom URL, sorry' unless Link.first(:identifier => custom).nil?
My Rails (with find)
raise 'Someone has already taken this custom URL, sorry' unless Link.find(:identifier => custom).nil? #this Link.find
Original context was a method that shortens urls
def self.shorten(original, custom=nil)
url = Url.first(:original => original)
return url.link if url
link = nil
if custom
raise 'Someone has already taken this custom URL, sorry' unless Link.first(:identifier => custom).nil?
raise 'This custom URL is not allowed because of profanity' if DIRTY_WORDS.include? custom
transaction do |txn|
link = Link.new(:identifier => custom)
link.url = Url.create(:original => original)
link.save
end
else
transaction do |txn|
link = create_link(original)
end
end
return link
end
You can just use a validator on the model. Just do a validates_uniqueness_of :first_name in the Url model (app/models/url.rb). There are also other validations available in the Rails guides
EDIT
If you really want to find if such a record exists manually. You can just do Url.find(:first, :conditions => { :first_name => 'original' }) and check for nil
raise 'Someone has already taken this custom URL, sorry' unless Link.find(:first, :conditions => { :identifier => custom }).nil?
Also, if you are new to rails might want to look at the query interface. Personally, I like to use the squeel gem so my queries are strictly ruby instead of mixing ruby and sql statements.

How to show search results on rails event_calendar?

I'm new to Rails and I am using rails event_calendar plug-in on my project. I implement it basic CRUD (Create, Read, Update, Delete ) operations on events. But now I need to show my search results on event_calendar. So please can some one give me an idea to implement this on event_calendar ??
From the event_calendar README:
The EventCalendar.new method accepts a hash or block of options, for example:
#event_calendar = EventCalendar.new(2009, 10, :id => 'calendar', :events => Event.all)
#event_calendar = EventCalendar.new(2009, 10) do |c|
c.id = 'calendar'
c.events = Event.all
end
So, instead of Event.all, just use whatever code you're using to get your filtered results.

Sorting in rails using helper

I'm a novice in ruby-on-rails.
I have an applications counting distance between metro station and a ATM.
There's two models with many-to-many relation: Station, Cashpoint. And there's a controller SHOW, that should get the station and show ATMs in order there's proximity to the station.
class StationsController < ApplicationController
def show
#station = Station.find(params[:id])
#cashpoints = #station.cashpoints.find(:all)
respond_to do |format|
format.html
end
end
end
Also there's a helper that counts distance using Google Directions API.
module StationsHelper
def count_distance(origin,destination)
...
return {:text => ... # 1 min
, :value => ... # 60 (seconds)
}
end
end
All this works properly.
But I'm wondering how to order ATMs by :value returned by StationsHelper?
I tried to write something in controller similar to:
#cashpoints = #station.cashpoints.find(:all,
:order => count_distance(#station.address, cashpoint.address)[:value])
But it's evidently doesn't work 'cause I have know idea how to link single cashpoint object
to count_distance method parameter.
May be you can help me, it appears that my project structure is wrong to do this.
Try this:
#cashpoints = #station.cashpoints.find(:all).sort_by { |c| count_distance(c.address, #station.address) }

Can I send instance variables to Tequila (.jazz) JSON Parser? (Ruby on Rails)

I am using the great Tequila-JSON Parser ( http://github.com/inem/tequila ) in an Web-application, to render more or less complex JSON server-replies. More and more the JSON-Templates (.jazz) are growing in somehow real "views". I am trying now, to get an instance-variable from the according controller, into the .jazz template, but this somehow fails.
Here is what I am trying to do.
The controller
def get_userlist
#users = User.find(:all, :order => "value DESC", :limit => 10)
#user = User.find_by_email(params[:user_email])
#userid = #user.id # also tried: #userid = 2
respond_to do |format|
format.json
end
end
The .jazz view:
-#users
:only
.nickname
.level
.user_icon_url
.email
:methods
.isfriend(#userid)
+last_checkin
+last_checkin_place
:only
.name
.city
This all returns a pretty valid JSON server-reply, but unfortunately, there is a problem with the
:methods
.isfriend(#userid)
The Method "isfriend" resides in the model "User", is called successfully and returns in the JSON, what it should. But the value of the instance-variable somehow is wrong. Opposed to the above, this one works fine:
:methods
.isfriend(1)
Now the question: Is Tequila not able, to interpret instance-variables in its own .jazz templates? Does anyone have experience, solutions or workarounds?
For the sake of completeness, here is the isfriend method of the User-Model:
def isfriend(user_id)
"Hi, I am User with the id: " + user_id.to_s
end
Nope. Also it doesn't work on Rails 3. I just spent 6 hours trying to port it and got basically nowhere :-(

Resources