views:

532

answers:

6

I'm about to build my first Ruby on Rails application (and first anything beyond xhtml and css), and I'm looking for some helpful feedback on my model structure.

I've included a mockup to help visual the application.

The only models I'm sure I need so far are:
1. a movie model (to serve as the main model, named movie so URL's will look like, "sitename.com/movies/1-Willy-Wonka") and
2. a user model

Other than those, I don't know what to make the others; like 'filming locations', 'actors', and most importantly, the attributes like 'willy wonka' and 'johnny depp'.

Should I make all of those models, even the attributes? If so, is it possible, and recommended, to let people create models as attributes?

I try to see the app as data created by forms and stored in databases, and with that pov I can't decide how to connect attributes (character <=> actor) to sections (actors, filming locations, artwork, etc.) inside a movie listing; while allowing the attributes themselves to be hyperlinks to related attributes/movies/even sections: clicking on 'steven speilberg' would bring you to a page with movies he's acted in, films he's directed, produced, written, etc.

Thoughts?

+2  A: 

I would recommend getting your data model clear first. You can then start with one rails model per database table. This is not always the case, but it's a reasonable place to start.

Let's focus on the movies and actors:

Some assumptions:

  • movies can have a many-to-many relationship to the other entities
  • you want to store the character information as part of the relationship between an actor and a movie

You might then model your relationships like this:

# movies.rb
class Movie < ActiveRecord::Base
  has_many :roles
  has_many :actors, :through => :roles
end

# actor.rb
class Actor < ActiveRecord::Base
  has_many :roles
  has_many :movies, :through => :roles
end

Normally, you can rely on Rails' magic to handle the join model without creating one yourself. In this case we want to store the character information as attributes of the join model, so we create it explicitly.

# role.rb
class Role < ActiveRecord::Base
  belongs_to :movie
  belongs_to :actor
end
Abie
has_many is for one-to-many relationships. For many-to-many relationships you need to do either has_and_belongs_to_many or has_many_through
toby
See comment regarding attributes on the join model.
Abie
So in practice, I should scaffold a model named Actor with 2 text strings called 'character' and 'actorsname'?And that'd be it? Do that for each section, connect through relationships, and that would - in a nutshell - be it?
Clayton Bellmor
Hang on, I'll post migrations that should clarify.
Abie
+2  A: 

Start with models Movie, Actor, FilmLocation, and Character. Movie and Actor have a many-to-many relationship(A Movie has many actors, an actor worked on many movies). FileLocation and Movie also are many-to-many. Character(Willy Wonka) and Actor are many-to-many as well.

toby
If you store movies, characters, and actors in three separate tables, maintaining the relationships could become onerous and error-prone.
Abie
Tables also refers to models, right? Because when you create a new model and run migration, it creates a database table with the model name?
Clayton Bellmor
Abie, I hope and pray that you're being sarcastic.
adolfojp
+2  A: 

If this is your first anything as far as web development then I suggest you start with writing a simple web app that just lists movies and allows your to add, edit and delete them. Just store the title, a synopsis and maybe the URL of the movie poster/dvd cover. Then work on adding Actors and associating them with the Movie.

Creating an "IMDB-like" site is not a trivial project. You're going to have a lot complex relationships beyond just associating an actor with a movie. Actors have Roles in Movies. And you might want to get even more abstract than that and say that a Person has Job in a Movie which would allow you to also track things like the Directors, Producers, Key Grips, Casting Directors.

Not only should you work on your data model, but work on a plan about what you want the site to consist of and what order you should create those features in (based on need) and take small steps to get to that final goal.

spilth
+1  A: 

In general, yes. I like my models to be as granular as possible. This makes things much clearer for someone who isn't familiar with the application and makes it easier to reuse code.

It's helpful to have a firm grasp of ActiveRecord associations before writing a complex application. Make sure you know all of the associations by heart and what they actually generate in terms of SQL tables. Sometimes it can seem like magic, and magic isn't necessarily a good thing. If you know what's behind it things fall in to place.

Also, don't be afraid to scrap everything and start over while experimenting. It's Ruby, so it won't take long to get back to where you were.

maxhawkins
+2  A: 

Further elaboration. The migrations for the models listed above might look like this:

class CreateMovies < ActiveRecord::Migration
  def self.up
    create_table 'movies' do |t|
      t.string  'title', :null => false
      t.timestamps
    end
  end

  def self.down
    drop_table 'movies' 
  end
end

class CreateActors < ActiveRecord::Migration
  def self.up
    create_table 'actors' do |t|
      t.string  'first_name', 'last_name', :null => false
      t.timestamps
    end
  end

  def self.down
    drop_table 'actors' 
  end
end

The movie_id and actor_id fields below correspond to the belongs_to associations in the Role model above and are the foreign keys that allow the roles table to join actors and movies. As I have proposed modeling it, the character_name is a property of this relationship, and is thus an attribute of the role. It's your call whether you allow NULL in the character_name. I'm leery of NULL, but in this case I've allowed it as one could make the argument that in practice you often wish to store the fact that an actor is in a given movie but don't know or care about the character name.

class CreateRoles < ActiveRecord::Migration
  def self.up
    create_table 'roles' do |t|
      t.integer 'movie_id', 'actor_id', :null => false
      t.string 'character_name'
      t.timestamps
    end
  end

  def self.down
    drop_table 'roles' 
  end
end
Abie
+2  A: 

It might be worthwhile to read up on database normalization: http://en.wikipedia.org/wiki/Database_normalization

Kevin Davis