0

I am getting to grips with DataMapper on sqlite3 at the moment. I have to models defined which are creating two tables: "companies" and "apps".

Each app belongs to a company and each company many apps. I want to represent this relationship in my models but I add the "has n" and "belongs_to" methods to each class, the App class stops working when call #create on a bunch of apps, they are not inserted into the database.

If I don't have the associations methods then everything works fine.

This is my DataMapper code:

DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/app.db")

class Company
    include DataMapper::Resource

    property :id, Serial
    property :company_name,
    property :company_id, Text, :unique => true

    has n, :apps
end

class App
    include DataMapper::Resource

    property :id, Serial
    property :app_id, Integer
    property :bundle_id, Text
    property :game_name, Text
    property :company_name, Text
    property :created_at, DateTime
    property :rank, Integer

    belongs_to :company
end

DataMapper.finalize.auto_upgrade!

puts 'Database and tables created'

This is the code I am using to populate my tables

companies_in_chart.each do |company|
    @add_company = Company.create(
        :company_name   => company["company_name"],
        :company_id     => company["company_id"]
    )
end
puts "Inserted companies into database"

apps_arr.each do |app|
    @new_app = App.create(
        :app_id         => app["app_id"],
        :bundle_id      => app["bundle_id"],
        :game_name      => app["game_name"],
        :company_name   => app["company_name"],
        :created_at     => app["DateTime"],
        :rank           => app["rank"]
    )
end
puts "Inserted apps into database"

EDIT: New code

#Set up database and apps table
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/app.db")

class Company
    include DataMapper::Resource

    property :id, Serial
    property :company_name, Text,    :required => true, :lazy => false
    property :company_id, Text,      :required => true, :lazy => false, :unique => true

    has n, :apps
end

class App
    include DataMapper::Resource

    property :id, Serial
    property :app_id, Integer,      :required => true
    property :bundle_id, Text,      :required => true, :lazy => false
    property :game_name, Text,      :required => true, :lazy => false
    property :company_id, Text,     :required => true, :lazy => false
    property :created_at, DateTime
    property :rank, Integer

    belongs_to :company
end

DataMapper.finalize.auto_upgrade!

puts 'Database and tables created'

#Insert apps and companies into database
apps_arr.each do |app|

    # Creates a new company based on app entry if the company does
    # not exist in the companies table
    @add_company = Company.create(
        :company_name   => app["company_name"],
        :company_id     => app["company_id"]
    )

    @add_app = App.create(
        :app_id         => app["app_id"],
        :bundle_id      => app["bundle_id"],
        :game_name      => app["game_name"],
        :company_id     => app["company_id"],
        :created_at     => app["DateTime"],
        :rank           => app["rank"]
    )
end
puts "Inserted app and companies into database"

@company = Company.first
ap @company # => #<Company @id=1 @company_name="Rovio Entertainment Ltd" @company_id="rovio">

ap @company.apps # => [] --I was hoping it would return all of Rovio's apps in the database

1 Answers1

3

apps not created cause you have to attach a company when creating app.

if you want to add apps not attached to any company, use this in you App model:

belongs_to :company, :required => false

to attach a company when creating app:

#Insert apps and companies into database

apps_arr.each do |app|

  # Creates a new company based on app entry if the company does
  # not exist in the companies table

  company = Company.first_or_create(
    :company_name   => app["company_name"],
    :company_id     => app["company_id"]
  )

  app = App.first_or_create(
    :company        => company, # you missed this
    :app_id         => app["app_id"],
    :bundle_id      => app["bundle_id"],
    :game_name      => app["game_name"],
    :company_id     => app["company_id"],
    :created_at     => app["DateTime"],
    :rank           => app["rank"]
  )
end
puts "Inserted app and companies into database"

I successfully replicated your code on CIBox and it runs perfectly.

See the code and live demo here

As you can see, it creates a company and attach it to created app.

Company.first.apps returns created app, so associations works correctly.

  • Thanks for the reply. I have tried to do as you suggest to the best of my understanding. Please see my question for my new code. – Stanislav Beremski Nov 10 '12 at 12:56
  • Okay. I changed my code by adding `:company => company` and I also changed the symbols `:add_app` and `:add_company` to the variable `company` and `a` (I didnt user `app` as you suggested because that variable name is already being used by `each.do |app|`. This code does add all the app and companies into their tables but `company.first.apps` still returns an empty array as opposed to all the apps by the first company so I don' think the associations are working. – Stanislav Beremski Nov 10 '12 at 15:18
  • Oh and I also tried changing `company = Company.first_or_create(...)` to `c = Company.first_or_create(...)` but then I am getting the error "in `block in ': undefined local variable or method `company' for main:Object (NameError)" as its not recognising the variable `company` in `:company => company` – Stanislav Beremski Nov 10 '12 at 15:23
  • you need to tune up a bit your code. [**here**](http://cibox.org/slivu/stackoverflow?path=why-is-one-of-my-tables-not-being-populated-if-i-use-datamappers-has-n-and-b&lang=ruby) is how i would reorganize it. also see updated answer for live working demo. –  Nov 10 '12 at 16:07
  • Thanks very much for your help. I think I got it working. You are totally right: I need to refactor a whole bunch of things which I think is going to be the next task! Interestingly your code seemed to generate two indexes: `unique_companies_company_id` and `index_apps_company`. My code never generated the second one which is required it would seem. Thanks for your help again! – Stanislav Beremski Nov 10 '12 at 16:59