Search code examples
rubyactiverecordmigrationsyntax-errorrake

Keep getting syntax error when "rake db:migrate"


My code:

class Song < ActiveRecord::Base
   belongs_to :artist
   has_many :song_genres
   has_many :genres, :through :song_genres
end

Error:

rake aborted!
SyntaxError: .../app/models/song.rb:4: syntax error, unexpected ':', expecting keyword_end
has_many :genres, :through :song_genres

When I use "=>":

class Song < ActiveRecord::Base
  belongs_to :artist
  has_many :song_genres
  has_many :genres, :through => :song_genres
end

I don't get an error message anymore but now I get another error message for a similar situation in one of my migrations.

rake aborted!
SyntaxError: .../db/migrate/01_create_artists_table.rb:4: syntax error, unexpected tSYMBEG, expecting keyword_end
                t.string :name

And the code there looks like this:

class CreateArtistsTable < ActiveRecord::Migration
  def change
        create_table :artists |t|
        t.string :name
        t.has_many :songs 
        t.has_many :genres, through: :song_genres 
        end 
  end
end

Im a newbie so I would really appreciate the help! Thanks! :)


Solution

  • You've got two problems here. In your model, you're getting the syntax for keyword arguments wrong. In ruby, you can pass arguments as keywords by putting the colon after the keyword and before the value, like so key: :value rather then :key :value. The colon before a word declares a symbol, which isn't what you're doing here. So, your model should actually be this:

    class Song < ActiveRecord::Base
       belongs_to :artist
       has_many :song_genres
       # has_many :genres, :through :song_genres
       has_many :genres, through: :song_genres
       # Which is shorthand for `has_many :genres, :through => :song_genres`
    end
    

    And, in your migration, you can't specify through. That's something that only exists in your models. You've also got the syntax for a migration wrong. It should look more like this:

    create_table :table_name do |t|
      t.type :column_name
    end
    

    When you say t.has_many, you're asking ActiveRecord to create a column with type "has_many" which isn't a valid type. Instead, you want something like string, integer, datetime, etc. For a reference to another table, you can do t.references. So, your migration should look more like this:

    class CreateArtistsTable < ActiveRecord::Migration
      def change
            create_table :artists |t|
            t.string :name
            t.<type> :songs 
            t.<type> :genres #, through: :song_genres 
            end 
      end
    end
    

    Specifically, given the relationships you're trying to create, it'll be more like this:

    class CreateArtistsTable < ActiveRecord::Migration
      def change
        create_table :artists |t|
          t.string :name
        end 
        add_reference :songs, :artist
        create_table :song_genres do |t|
          t.references :song
          t.references :genre
        end
      end
    end
    

    As a side note, in ruby you should be using 2 spaces for indentation.