Rails Fixtures without Name - ruby-on-rails

Is it possible to create fixtures without a name? Something like:
--:
name: ...
description: ...
--:
name: ...
description: ...

No, you can't you'll have to use a random name. If you take a look at the insert_fixtures function you'll notice that it depends on a fixture label to do it's work. To see this in action, try creating a sample yml file like this:
# sample.yml
a:
value: 'hi'
a:
value: 'world'
And then loading it in Ruby:
YAML.load(File.open('sample.yml').read)
You'll get this result:
{"a"=>{"value"=>"world"}}
That's because of the way YAML loads hashes. The keys are distinct, so you need to have unique keys in your yaml files. That's why the fixtures code depends on a unique label.

In the end, your fixtures will be added to your test database anyway, creating models and calling save, so why spending time converting the XML to YAML or CSV when you can just parse your XML and seed your database?
This way you'll have less work to do when adding new data to your tests or extending the scope of your testing.

Related

How to fill model(database) in ruby on rails with json file?

I have a json file with a lot of movies in it. I want to create a model 'Movie' and fill it with all movies from that json file. How do i do it? I know that I can parse json file into a hash but that's not the thing I am looking for.
The correct term you're looking for is "seeding"!
You're going to need a database however, and a migration to create the database along with the associated movies table. (There are plenty of guides on how to do this, along with the official documentation).
After that's done, you'll need to "seed" your database with the data in your json file.
In the seeds.rb file, assuming that the JSON file is an array of Movies in JSON form, you should be able to loop over every Movie JSON object and insert it into your database.
To add to docaholic's helpful response, here's some steps/pseudo-code that may help.
Assuming you're using a SQL database and need to create a model:
# creates a migration file.
rails generate migration create_movies title:string #duration_in_minutes:integer or whatever fields you have
# edit the file to add other fields/ensure it has what you want.
rake db:migrate
Write a script to populate your database. There are many patterns for this (rake task, test fixtures, etc) and which one you'd want to use would depend on what you need (whether it's for testing, for production environment, as seed data for new environments, etc).
But generally what the code would look like is:
text_from_file = File.read(file_path)
JSON.parse(text_from_file).each do |json_movie_object|
Movie.create!(title: json_movie_object[:title], other_attribute: json_movie_object[:other_attribute])
# if the json attributes exactly match the column names, you can do
# Movie.create!(json_movie_object)
end
This is not the most performant option for large amounts of data. For large files you can use insert_all for much greater efficiency, but this bypasses activerecord validations and callbacks so you'd want to understand what that means.
For my case, I need to seed around 200 hundred datas for production from a JSON file, so I tried to insert data from the json files in a database.
SO at first I created a database in rails project
rails generate migration create_movies title:string duration_in_minutes:integer
# or whatever fields you have
# edit the file to add other fields/ensure it has what you want.
rake db:migrate
Now its time to seed datas!
Suppose your movies.json file has:
[
{"id":"1", "name":"Titanic", "time":"120"},
{"id":"2", "name":"Ruby tutorials", "time":"120"},,
{"id":"3", "name":"Something spetial", "time":"500"}
{"id":"4", "name":"2HAAS", "time":"320"}
]
NOW, like this 4 datas, think your JSON file has 400+ datas to input which is a nightmare to write in seed files manually.
You need to add JSON gem to work. Run
bundle add json
to work with JSON file.
In db/seed.rb file, add these lines to add those 400+ infos in your DATABASE:
infos_from_json = File.read(your/JSON/file/path/movies.json)
JSON.parse(infos_from_json).each do |t|
Movie.create!(title: t['name'], duration_in_minutes:
t['time'])
end
Here:
infos_from_json variable fixing the JSON file from file directory
JSON.parse is calling the JSON datas then the variable is declared to indicate where the file is located and each do loop is dividing each data and |t| will be used to add part JSON.parse(infos_from_json). in every call.
Movie.create!(title: t['title'], duration_in_minutes: t['time']) is adding the data in database
This is how we can add datas in our database from a JSON file easily.
For more info about seeding data in database checkout the documentation
THANKS
Edit: This operation requires JSON gem just type bundle add json

Seed data vs class hashes

I am writing a browser based RPG and I am trying to figure out the best way to store "seed" data, ie. data like locations, monsters and items, that are standard entities of the game.
Would it be best to store this in a "def self.items.." hash in which i keep all the different items, or should I put them in a database and seed them? If I should seed them, what is the best way to accomplish this, just fill up the seed.rb files with 200-300 different instances or keep them in other files?
I absolutely hate cluttered seed files. Admittedly, it's a personal preference and not a right or wrong.
Here's what I did in my app at work to handle the significant volume of seed data we are required to use:
# Folder Structure
db
schema.rb
seeds.rb
seeds/
01_organization.rb
02_real_estate_industry.rb
03_click_types.rb
...
My seeds.rb file:
# All seeds are broken out into ordinally names files inside the db/seeds/* directory.
Dir[File.join(Rails.root, 'db', 'seeds', '**/*.rb')].each do |file|
require file
end
A sample seed file in the seeds/ folder:
organizations = Organization.all
Organization.create(
{
name: 'CompanyName',
blurb: 'Hi. I am a blurb.',
city: 'Some City',
state: 'ST',
web: 'http://www.somewebsite.com',
phone: '1-000-555-1212'
}
) if organizations.empty?
This has the effect of loading our seed files in the desired order (using 01_ then 02_, etc.). It also breaks up our seeds into logical groupings and organizes them in such a way that, for our team, we can more easily manage them.

How to use ruby-on-rails fixtures for setting up (external) data that does not belong to the rails app DB?

Per my requirements, I have created models for querying external database (different from the one that the rails app uses) for some of the data.
I am trying to write tests around these models and want to separate the "sample test data" from the actual tests.
I thought I could put the data in a yml file and load it into a hash, but it did work out :(
Added sample test data to a fixture file name 'external_database.yml'
Put the below code in setup, in the test file
ext_data = YAML.load_file(Rails.root.to_s + "/test/fixtures/ext_data.yml")
But I am stuck with the below error
1) Error:
test_should_errorout_for_invalid_market_zip(ExtDBTest):
ActiveRecord::StatementInvalid: Mysql::Error: Table 'rails_app_db.ext_data' doesn't exist: DELETE FROM ext_data
What is the best way to do what I want done?
I guess your problem is that the schema of that external database is not contained in your schema.rb-file and/or migrations. These are used to setup your test-database before you run the tests.
So the attempt is made to write those fixtures into non-existing tables - with the result you see above.
Multiple database-connections in unit tests are generally a pain. Consider creating an sqlite-file for the data of the external dependencies and configure your test-environment to use this file - or a copy of it, in case you need to mutate data.

How can I load some ActiveRecord models from a YAML file and save them to the DB?

I'm trying to save some lookup table data out to a YAML file so that later when I need to set up my app on a different machine I can load the data in as seed data.
The data is stuff like select options, and it's pretty much set, so no worries about the live data changing between serializing and deserializing.
I have output the data like this...
file = File.open("#{RAILS_ROOT}/lib/tasks/questions/questions.yml", 'w')
questions = Question.find(:all, :order => 'order_position')
file << YAML::dump(questions)
file.close()
And I can load the file like this...
questions = YAML.load_file('lib/tasks/questions/questions.yml')
However, when I try to save a question I get this error...
>> questions[0].save
NoMethodError: undefined method `save' for #<YAML::Object:0x2226b84>
What is the correct way to do this?
Create a seed.yml file in db directory. Add a YAML document for each model you want to create. This document should contain a list of hash. Each hash should contain model attributes.
users:
- login: jake
password: jake123
password_confirmation: jake123
first_name: Jake
last_name: Driver
- login: Jane
password: jane123
password_confirmation: jane123
first_name: Jane
last_name: McCain
categories:
products:
In your seed.rb file
seed_file = File.join(Rails.root, 'db', 'seed.yml')
config = YAML::load_file(seed_file)
User.create(config["users"])
Category.create(config["categories"])
Product.create(config["products"])
Run the rake task to load the rows
rake db:seed
Does the accepted answer actually answer the question? It looks like the asker wanted to save the models, not just retrieve them from a YAML file.
To actually save the loaded model(s) back to the database you need to fool ActiveRecord into thinking the model needs saving. You can do it with this rather dirty bit of code
questions = YAML.load_file("#{RAILS_ROOT}/lib/tasks/questions/questions.yml")
questions.each{|q| q.instance_variable_set("#new_record", true); q.save}
It works and saved my bacon once or twice.
I tried your scenario and I did not have any issues. I did the following changes to your YAML file creation logic:
yml_file = Rails.root.join('lib', 'tasks', 'questions', 'questions.yml')
File.open(yml_file, 'w') do |file|
questions = Question.order(:order_position).to_a
YAML::dump(questions, file)
end
I was able to retrieve the questions list as follows:
yml_file = Rails.root.join('lib', 'tasks', 'questions', 'questions.yml')
question_attributes_list = YAML.load_file(yml_file).map(&:attributes)
questions = Question.create(question_attributes_list)
If you're using Rails 2.3.4 (or above), they have a seeds.rb file that can be found in your applications db folder. This lets you define basic active record creates, and when you've set up your new project, you can simply call:
rake db:seed
There is an excellent Railscast on it here, and a good blog post about it here. If you're not using Rails 2.3.4 (Or, ideally, 2.3.5), I highly recommend updating for these cool features, and addition security/bug fixes.

Using fixtures without a corresponding model in Rails

I currently have some large strings that I would like use as test data when testing a log scraper. It would work well to have these strings in a YAML file.
I would love to refer to them while testing in a short and concise manner such as:
log_lines(:incorrect_string)
Is there anyway to do this using fixtures, or are they exclusively for use with a corresponding model?
If your yaml looks like this:
:incorrect_string: blah
then you can just
logs = YAML::load_file('filename')
p logs[:incorrect_string]
cheer!

Resources