Topic: Need help understanding Relationships with Rails from PHP background

In PHP/MySQL, here is my database model where each state can have many categories:

categories (id,folder,name)
state_categories (state_id,categories_id,title,description,keywords)
states (id,abbr,name)

How do I translate this methodology into Rails relationships since it is not the simple has_many & belongs_to?

Re: Need help understanding Relationships with Rails from PHP background

Actually this is pretty good already.  You can hook it all together like this:

class Category < ActiveRecord::Base
  has_many :state_categories
  has_many :states, :through => :state_categories
end
class StateCategories < ActiveRecord::Base
  belongs_to :state
  belongs_to :category
end
class State < ActiveRecord::Base
  has_many :state_categories
  has_many :categories, :through => :state_categories
end

that should do it!

edit: I see that you've got "categories_id".  That should be "category_id" (singular).  If, for whatever reason, you can't change it make sure to do this:

belongs_to :category, :foreign_key => :categories_id

Re: Need help understanding Relationships with Rails from PHP background

Thanks! You are correct; it should be category_id. For my PHP/MySQL table named state_categories, what is the best Rails practice for creating that controller and what should I rename the table to, if necessary?

script/generate object state(s)_categor(y|ies)
script/generate object state(s)-categor(y|ies)
script/generate object state(s)categor(y|ies)
script/generate object State(s)Categor(y|ies)

Re: Need help understanding Relationships with Rails from PHP background

I like coming up with a more natural sounding word for the join tables.  So "state_categorizations" would be my preference.

If you're running a modern version of Rails you can get everything you need set up with the following:
script/generate resource category
script/generate resource state
script/generate resource state_categorization

This'll create a categories controller and a category model, etc.

Re: Need help understanding Relationships with Rails from PHP background

Awesome! It's so easy my PHP brain won't accept it. Am I using the below correctly and/or is there a more simple way?

@state_category = StateCategory.find(
    :first,
    :joins => 'LEFT JOIN `categories` ON `categories`.`id`=`state_categories`.`category_id`',
    :conditions => "`folder`='" + params[:folder] + "' AND `state_id`='" + SITEID + "'"
)

I've tried find_by_folder but I don't know how to join the tables to get it to work.

Last edited by ZootSuitRyan (2007-04-26 20:45:33)

Re: Need help understanding Relationships with Rails from PHP background

You'll love this :-)

@state_category = StateCategory.find_by_folder_and_state_id(params[:folder], SITEID, :include => :category)

Re: Need help understanding Relationships with Rails from PHP background

Wow, I do! The only problem is that I get an error message.  Here is my route and my state_category controller.

# routes.rb
map.connect ':folder', :controller => 'state_categories', :action => 'show', :defaults => { :folder => 'home' }

# state_categories_controller.rb
class StateCategoriesController < ApplicationController
  def show
    @state_category = StateCategory.find_by_folder_and_state_id(params[:folder], SITEID, :include => :category)
  end
end

# Action Controller: Exception caught
undefined method `find_by_folder_and_state_id' for StateCategory:Class

Last edited by ZootSuitRyan (2007-04-27 14:21:41)

Re: Need help understanding Relationships with Rails from PHP background

Ahh, I see.  'folder' isn't actually part of the state_categories table - it's in categories isn't it?

Okay, sorry about that wild goose chase.  Here's one that'll work:

StateCategory.find_by_state_id(SITEID, :conditions => ["categories.folder = ?", params[:folder]]:include => :category)

Re: Need help understanding Relationships with Rails from PHP background

No apologies necessary. I can always use the longer code for now. An error now displays looking for state_categories.id.  My current primary key is {category_id, state_id} so I don't have an ID field.  Is it "best practice" to have an ID field for every table or is there a work around?

I have tried :select but whatever I enter for :select => "" is ignored.

Last edited by ZootSuitRyan (2007-04-27 20:50:23)

Re: Need help understanding Relationships with Rails from PHP background

Any table that has an explicit model in app/models will need to have an id field in it.  You can only get away with having no id if you're using the old has_and_belongs_to_many relationship which Rails is moving quickly away from.

Re: Need help understanding Relationships with Rails from PHP background

im not sure if this can apply, but why not use Acts_As_Tree?

that way, you can easily sort categories and states like a tree. Just have one large table called  "Element" with all the common fields(title,id, parent_id) as well as each individual specific attributes(state, abbr, keywords, description, other foreign_keys). The children method will allow you to manipulate any child from any node.

country = Element.create(:name => "US of A")
state = country.children.create(:name => "Los Angeles", :abbr => "LA")
category = state.children.create(:name => "Autos", :keywords => "Cars, Insurance", :description => "All Cars in Los Angeles")

Re: Need help understanding Relationships with Rails from PHP background

Thanks jjk2, I'll check that out.

Another question: Why (and what) does find_by_state_id, for example, return a different object than plain find or find_all?

Re: Need help understanding Relationships with Rails from PHP background

find_by_state_id should return one model which matches the given state_id column. It behaves the same way this would:

Foo.find(:first, :conditions => ['state_id = ?', params[:state_id]])
# same as this...
Foo.find_by_state_id(params[:state_id])

Railscasts - Free Ruby on Rails Screencasts

Re: Need help understanding Relationships with Rails from PHP background

find_by_state_id and find_all_by_state_id are just like find and find_all except that they restrict the search to records with a matching state_id.  The returned objects should be identical.

The only gotcha is that find_all_by_state_id returns an array of record while find_by_state_id returns just the first record found.