trying to seed data from seeds.rb within a class structure

Hey all,

I created this in seeds.rb because I want to avoid duplication as much
as possible:

class DataGenerator
  def initialize
    @current_user = User.first
  end

  def posts!
    Title.each do |t|
      Body.each do |b|
        post! t, b, @current_user.id
      end
    end
  end
end

class StaticDataGenerator < DataGenerator
  def initialize
    super
    @created_at = "2011-04-04".to_date
    @updated_at = "2011-05-04".to_date
    @published = false
  end

  def post!(title, body, user_id, options = {})
    defaults = {
      :title => title,
      :body => body,
      :created => @created_at,
      :updated => @updated_at,
      :published => @published,
      :user_id => user_id
    }
    blog_post = BlogPost.create!(defaults.merge(options))
  end
end

class RandomDataGenerator < DataGenerator
  def initialize
    super
  end
end

Title = ["ABC","DEF","GHI","JKL"]
Body = ["MNO","PQR","STU","VWX"]

So basically what should happen is a new blog_posts record is written to
the database populated with default values like in the following sql
statement:
INSERT INTO blog_posts
(title,body,created_at,updated_at,published,user_id)
VALUES("ABC","MNO",2011-04-04,2011-05-04,0,1)

However, when I run rake db:seed, nothing happens. I suspect that it's
the class structure of my script that's not being triggered when I run
db:seed. Any idea how to address this?

Thanks for response.

Have you tried adding:

StaticDataGenerator.new.posts!

to the end of your file?

Have you tried adding:

StaticDataGenerator.new.posts!

Yeah, that would make sense. I have run into that before where validation or something fails. BYW, does anyone know if there is a way to invoke the debugger during rake db:seed or for that matter any other rake task? I dont think I have ever been successful at this. Maybe have to include ruby-debug or the like?

You can add --trace to the end of your rake command. It’s not a debug per se but will show you what is going on with the rake command at the time. I also like to add a puts statement at the beginning of any call in my rake file. Something like “Begin seeding posts…” then on the next call “Begin seeding comments…”. It helps when you didn’t or forgot to add the --trace flag to see where you are in the process in case it hangs.

B.

Kendall Gifford wrote in post #991124:

Have you tried adding:

  StaticDataGenerator.new.posts!

to the end of your file?

Thanks for response. yes, that worked. That makes sense that you need to
call a method in client code for it to do anything. I do have one
unexpected result. This method right here:

  def posts!
    Title.each do |t|
      Body.each do |b|
        post! t, b, @current_user.id
      end
    end
  end

I was expecting it to generate a combination like this:
"ABC" "MNO"
"DEF" "PQR"
"GHI" "STU"
"JKL" "VWX"

See how it corresponds index 0 of the Title array with index 0 of the
Body array and then index 1 of the Title array with index 1 of the Body
array and so forth.

But what my posts! method does is this:

"ABC" "MNO"
"ABC" "PQR"
"ABC" "STU"
"ABC" "VWX"
"DEF" "MNO"
"DEF" "PQR"
"DEF" "STU"
"DEF" "VWX"

and so forth. See how it generates index 0 of Title with all the indexes
of Body and does it for the other indexes of Title as well.

I believe it's my misunderstanding of the nested block:

   Title.each do |t|
      Body.each do |b|
        post! t, b, @current_user.id
      end
    end

I thought this would iterate through the first index of Title as local
variable t and then iterate through first index of Body as local
variable b and then pass them into argument list of post! And then when
the outer block ended, it would go to the next index and repeat same
process

Anyone know what I am doing wrong and how to get it to match index to
index not index to all the other indexes?

Thanks for response.

Kendall Gifford wrote in post #991124:

Have you tried adding:

StaticDataGenerator.new.posts!

to the end of your file?
Thanks for response. yes, that worked.

Cool.

That makes sense that you need to
call a method in client code for it to do anything. I do have one
unexpected result. This method right here:

def posts!
Title.each do |t|
Body.each do |b|
post! t, b, @current_user.id
end
end
end

I was expecting it to generate a combination like this:
“ABC” “MNO”
“DEF” “PQR”
“GHI” “STU”
“JKL” “VWX”

See how it corresponds index 0 of the Title array with index 0 of the
Body array and then index 1 of the Title array with index 1 of the Body
array and so forth.

But what my posts! method does is this:

“ABC” “MNO”
“ABC” “PQR”
“ABC” “STU”
“ABC” “VWX”
“DEF” “MNO”
“DEF” “PQR”
“DEF” “STU”
“DEF” “VWX”

and so forth. See how it generates index 0 of Title with all the indexes
of Body and does it for the other indexes of Title as well.

I believe it’s my misunderstanding of the nested block:

Title.each do |t|
Body.each do |b|
post! t, b, @current_user.id
end
end

Yes, what you were expecting would have been “parallel iteration” (any experts know if there is a more correct term for this?). What you did was “nested iteration” (?). In nested iteration (what you did) your variables at your “innermost” scope will, over the course of the iterations, describe the “cartesian product” (http://en.wikipedia.org/wiki/Cartesian_product) of the sets that you’re iterating over. So, with two sets a and b, the total number of combinations (tuples) will be a.length * b.length.

I thought this would iterate through the first index of Title as local
variable t and then iterate through first index of Body as local
variable b and then pass them into argument list of post! And then when
the outer block ended, it would go to the next index and repeat same
process

Anyone know what I am doing wrong and how to get it to match index to
index not index to all the other indexes?

One way to do what you want would be (assuming Title and Body will always contain the same number of elements):

def posts!
Title.each_with_index do |t, i|
post! t, Body[i], @current_user.id
end
end

I’m sure there are more clever, ruby-ish ways for parallel iteration that using #each_with_index.

P.S. - (nyone feel free to correct this or comment if I’m wrong here) here’s a style recommendation: constants such as Class instances (a.k.a class and module definitions or constants that “act” like them) are usually written with only the first letter capitalized. Constants of other types (like your arrays of strings) are usually ALL_CAPS.

P.P.S. - You may also be interested in the following Ruby syntactic sugar:

TITLE = %w{ ABC DEF GHI JKL }
BODY = %w{ MNO PQR STU VWX }

This of course only works when all the strings in your array are simple and don’t contain any whitespace.

One way to do what you want would be (assuming Title and Body will always contain the same number of elements):

def posts!
Title.each_with_index do |t, i|
post! t, Body[i], @current_user.id
end
end

I’m sure there are more clever, ruby-ish ways for parallel iteration that using #each_with_index.

Okay, I couldn’t help myself. Here’s another alternative/example for this kind of “parallel iteration”

fruits = %w{ apples pineapples oranges }
states = %w{ Washington Hawaii Florida }

states.zip(fruits) do |state, fruit|
puts “#{state} grows #{fruit}”
end

  def posts!
    Title.each_with_index do |t, i|
      post! t, Body[i], @current_user.id
    end
  end

each_for_index is very helpful. Thanks a lot for responses.

rdebug rake whatever

Colin