Topic: Could use some advise on this please

I would like to get some advice on this. smile

Coming from a php background, I can understand that this looks even much cleaner but I am hoping there is a much efficient way to do this. I am just a noob so please excuse my crude ways. I feel dirty like I made a ton of sql-string-like in php but disguised in Rails. hmm

I am trying to do everything restful. Its a cms-portal type that needs to be host city separated with directories that have multiple categories and have multiple subcategories and has guides and has events and has magazines per host city too. I eventually got what I wanted to do by example of my Chicago Controller and custom routes but it feels like a cheat. Is there a much better practice/way for this? I appreciate any help and direction. Thanks.

Here I have a directory model with its associations.

## Model
class Directory < ActiveRecord::Base
  validates_presence_of :host_city_id, :neighborhood_id, :company_id, :publish
  belongs_to :company
  belongs_to :host_city
  belongs_to :neighborhood
  has_many :events
  has_many :votes
  has_many :categorizations
has_many :categories, :through => :categorizations
has_many :subcategorizations
has_many :subcategories, :through => :subcategorizations
has_many :guideaddressables
has_many :guides, :through => :guideaddressables
end

My custom routes per host city by category which is drawn from the directories controller. It looks very very very very nasty if I have to map every darn host city like this.
## Routes
   map.resources :directories
   map.resources :subcategorizations
   map.resources :categorizations
   map.resources :companies
   map.resources :regions
   map.resources :votes
   map.resources :pages
   map.resources :events
  map.resources :neighborhoods
  map.resources :categories
  map.resources :host_cities
  map.resources :guides
  map.resources :tours
  map.resources :articles
  map.resources :magazines

  map.connect '/chicago/restaurant/', :controller => 'chicago', :action => 'restaurant'
  map.connect '/chicago/restaurant/:id', :controller => 'directories', :action => 'show'

  map.connect '/chicago/shopping/', :controller => 'chicago', :action => 'shopping'
  map.connect '/chicago/shopping/:id', :controller => 'directories', :action => 'show'
 
  map.connect '/chicago/nightlife/', :controller => 'chicago', :action => 'nightlife'
  map.connect '/chicago/nightlife/:id', :controller => 'directories', :action => 'show'

  map.connect '/chicago/entertainment_attractions/', :controller => 'chicago', :action => 'entertainment_attractions'
  map.connect '/chicago/entertainment_attractions/:id', :controller => 'directories', :action => 'show'

  map.connect '/chicago/accommodations/', :controller => 'chicago', :action => 'accommodations'
  map.connect '/chicago/accommodations/:id', :controller => 'directories', :action => 'show'
 
  map.connect '/chicago/transportation/', :controller => 'chicago', :action => 'transportation'
  map.connect '/chicago/transportation/:id', :controller => 'directories', :action => 'show'
 
  map.connect '/chicago/guides/', :controller => 'chicago', :action => 'guides'
  map.connect '/chicago/guides/:id', :controller => 'guides', :action => 'show'


The crazy controller ;p
## Chicago Controller
class ChicagoController < ApplicationController

  def index
    @restaurants = Directory.find(:all, :include => :categorizations, :order => 'created_at DESC', :limit => 5, :conditions => ["categorizations.category_id=? and featured=? and publish=? and host_city_id =?", 1, true, true, 1])
    @shoppings = Directory.find(:all, :include => :categorizations, :order => 'created_at DESC', :limit => 5, :conditions => ["categorizations.category_id=? and featured=? and publish=? and host_city_id =?", 2, true, true, 1])
    @nightlife = Directory.find(:all, :include => :categorizations, :order => 'created_at DESC', :limit => 5, :conditions => ["categorizations.category_id=? and featured=? and publish=? and host_city_id =?", 3, true, true, 1])
    @attraction = Directory.find(:all, :include => :categorizations, :order => 'created_at DESC', :limit => 5, :conditions => ["categorizations.category_id=? and featured=? and publish=? and host_city_id =?", 4, true, true, 1])
    @accommodation = Directory.find(:all, :include => :categorizations, :order => 'created_at DESC', :limit => 5, :conditions => ["categorizations.category_id=? and featured=? and publish=? and host_city_id =?", 5, true, true, 1])
   @transportation = Directory.find(:all, :include => :categorizations, :order => 'created_at DESC', :limit => 5, :conditions => ["categorizations.category_id=? and featured=? and publish=? and host_city_id =?", 6, true, true, 1])
   @guides = Guide.find(:all, :order => 'created_at DESC', :limit => 5, :conditions => ["featured=? and publish=? and host_city_id =?", true, true, 1])
  end

  def restaurant
    @restaurant = Categorization.find(:all, :include => :directory, :joins => "LEFT JOIN companies c ON company_id = c.id", :conditions => ["categorizations.category_id=? and host_city_id =?", 1, 1], :order => 'c.name')
  end

  def shopping
    @shopping = Categorization.find(:all, :include => :directory, :joins => "LEFT JOIN companies c ON company_id = c.id", :conditions => ["categorizations.category_id=? and host_city_id =?", 2, 1], :order => 'c.name')
  end

  def nightlife
    @nightlife = Categorization.find(:all, :include => :directory, :joins => "LEFT JOIN companies c ON company_id = c.id", :conditions => ["categorizations.category_id=? and host_city_id =?", 3, 1], :order => 'c.name')
  end

  def entertainment_attractions
    @attraction = Categorization.find(:all, :include => :directory, :joins => "LEFT JOIN companies c ON company_id = c.id", :conditions => ["categorizations.category_id=? and host_city_id =?", 4, 1], :order => 'c.name')
  end

  def accommodations
    @accommodation = Categorization.find(:all, :include => :directory, :joins => "LEFT JOIN companies c ON company_id = c.id", :conditions => ["categorizations.category_id=? and host_city_id =?", 5, 1], :order => 'c.name')
  end

  def transportation
    @transportation = Categorization.find(:all, :include => :directory, :joins => "LEFT JOIN companies c ON company_id = c.id", :conditions => ["categorizations.category_id=? and host_city_id =?", 6, 1], :order => 'c.name')
  end
end

=====================
Sam G.

Re: Could use some advise on this please

Wow ... hard to tell where to start wink We've all been there ..

- One Controller for each City is totally NOT DRY.... and what you are doing is not REST at all.
- I see you definately want URLs Like http://somedomain.com/CITY-HERE/action-here
- If this is a must, RESTful URLs and Resources won't work here anyways.

There's much to refactor, i've got not enough time now so just some hints:

1) Associations

 class Directory < ActiveRecord::Base
   # I guess "Diretories" are in fact "places like restaurants, shops etc?
   # think of changing the model name to represent that

   belongs_to :company
   belongs_to :host_city
   belongs_to :neighborhood
   has_many :events
   has_many :votes
   has_many :guideaddressables
   has_many :guides, :through => :guideaddressables
   New Categories:
   has_many :categorizations
   has_many :categories, :through => :categorizations
# end

class Category < ActiveRecord::Base
  acts_as_nested_set
  #http://api.rubyonrails.org/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html
  #http://api.rubyonrails.org/classes/ActiveRecord/Acts/NestedSet/InstanceMethods.html
  #This Rails Act lets you build a Tree aof nested (sub)categories in a single table

  has_many :categoritations
  has_many :directories, :through => :directories
  # each categorie has many directories, each directory can belong to many categories.
end

...
.....


2) Routing
Change a lot here:
- remove the map.resources, as - for the frontend - you won't be able to use them anyways because of the "pretty URLs". you could however use them for the admin backend or sth.
- blabla.com/Chicago should show the index action of a CitiesConTroller
- blabla.com/Chicago/restaurants should show the "show" action of the CategoriesController

# Your REST Routes for the 

#Default Routes. As to be before the Cities Route to catch other actions.
map.connect :controller/:action/:id.format
map.connect :controller/:action/:id


# route To Categories controller - show action
# Created params: params[:city], params[:category]
map.connect ':city/:category',:controller => "categories", :action => "show"

# Route to Cities controller - index action
# created params: params[:city]
map.connect ':city', :controller => "city", :action => "index"


3)

class CityConController < ApplicationController::Base


def index

  @city  = HostCity.find_by_name(params[:city]
  if !@city
    redirect_to SOMEHWERE-BECAUSE-CITY-WAS-NOT-FOUND
  end

@category = Category.find_by_name params[:category],
           :include => [:directories],
           :conditions => [directories.host_city_id = ?, @city.id],
           :limit => 5
           :order => "directories.created_at DESC"

  @directories = @category.directories
  # render a view
end

end


...and so much more but it's late and i got to go to bed ...
hope it gives ya some pointers ...

Last edited by Duplex (2007-07-10 18:41:43)