In my product model, I have an images json type column, for storing
multiple product images through Carrierwave in an array. I'm using Postgresql.
t.json "images"
I made a rake task to import products, that imports the images from a JSON file that contains images like this:
In my rake task:
record = Product.find_or_create_by(
images: item['AllImages'].to_json
}
I'm getting the error:
No operator matches the given name and argument types. You might need to add explicit type casts.
¿Am I missing something?
Related
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
I'm working on a ruby gem which can generate some code in other language. The gem needs to load the models in the current rails app. And it's implemented as a generator which accepts one parameter -- the table name. Inside it, read the columns definition from that table in this way:
tableklass = table_name.to_s.constantize # get the class name from table_name
cols = tableklazz.columns # get columns definitions.
When I run the generator 'rails g mygen Product'. It always gave me the error below:
.../ruby/gems/2.3.0/gems/activesupport-4.2.4/lib/active_support/inflector/methods.rb:261:in `const_get': wrong constant name products (NameError)
How can I fix this error? Or whether is there other better way to do so (read table information to generate some code)?
constantize expects camelized input. I am not sure, what is happening inside your generator, but it looks like constantize finally receives products as a parameter. Safest version of what you are trying to do:
table_name.to_s.singularize.camelize.constantize
Everything below would work:
:products.to_s.singularize.camelize.constantize
:product.to_s.singularize.camelize.constantize
'product'.to_s.singularize.camelize.constantize
Product.to_s.singularize.camelize.constantize
I am trying to use Carrierwave with multiple image uploads.
After following the carrierwave guide on github I do:
rails g migration add_images_to_areas images:json
rake db:migrate
But seeing on my schema, my areas table does not show up, instead I get:
# Could not dump table "areas" because of following StandardError
# Unknown type 'json' for column 'images'
What should I do now? Should I use another type instead of json, but what?
Sorry if this is an amateur question.
Databases by default don't support arrays, hashes and so on.
In order to do it, you can serialize it adding this code to your model:
class Name_class < ActiveRecord::Base
serialize :column_name, JSON
end
And change the migration field :
add_column :user_preferences, :text
This will insert the info as Text into the database and, when you retrieve it , it will be JSON.
More info about serialization here RailsGuides#Serialize
I am not sure as to what was going wrong here, The github tutorial of Carrierwave was suggesting :json, but you don't have to do so.
Everything went fine after I just followed the guide for multiple image upload with Carrierwave here: Rails 4 multiple image or file upload using carrierwave
I have a ruby script written which takes a CSV file and converts the input into a hash:
Culper = File.open('.\CulperCSV.csv')
culper_hash = {}
# set up culper code hash from provided CSV
CSV.foreach(Culper) do |row|
number, word = row
culper_hash[word] = number
end
and I am trying to make a Rails app using the script.
My question: How do I store the Hash persistently (or the CSV data so I can build the hash) so that I can minimize load times?
My thoughts:
1) Load the CSV data into a database (seed it) and each time I get a visitor on my site, do the above assignment into a hash but from the db. (not sure how to do this but I can research it).
or
2) Load the complete hash into the database (I think I would have to serialize it?) so that I can do just one fetch from the db and have the hash ready to go.
I am very new to building apps, especially in Rails so please ask questions if what I am trying to do doesn't make sense.
I suggest you should go with 2nd approach. Here are steps to do that:
Setup new app:
rails new app_name
bundle install
rake db:create
Create Model:
rails g model model_name column_name:text
rake db:migrate
Open model_name.rb file and add the following line
serialize :column_name
Now all sets. Just run the your script to parse .csv file and store hash in db. Your column is now able to store the hash.
Culper = File.open('.\CulperCSV.csv')
# get the object from database
obj = ModelName.first
# set up culper code hash from provided CSV
CSV.each(Culper) do |row|
number, word = row
obj.column_name[word] = number
end
obj.save
Your .csv file seems to be already in your Rails app directory, so load times shouldn't be bad (unless it's really big). However, if that file isn't going to change and you need only a small piece of it at a time, then I would store that in your database.
Create a model/migration that corresponds to the data you have in the .csv file and then (after migrating the migration) run a script to parse the data from your .csv file to your database.
I managed to solve my problem following the advice of #Kh Ammad: setting up a new app, creating a model for it, and marking my column serializable.
However, I had some problems with running the script to populate the model with the hash so instead, after some research, I created the rake task below:
#lib/tasks/import.rake
require 'csv'
task :import, [:filename] => :environment do
culper_hash = {}
Culper = File.open('.\CulperCSV.csv')
CSV.foreach(Culper) do |row|
number, word = row
culper_hash[word] = number
end
# culper_hash == column_name
obj = CulperDict.create(culper_hash: culper_hash)
obj.save
end
and ran it with:
$ bundle exec rake import
and my model contained the entire hash table in one entry!
I used this article to figure out how to run a rake task:
http://erikonrails.snowedin.net/?p=212
Specifically, the last comment on the page by Lauralee (posted on December 20th, 2012 at 8:47 am) who ran into a similar problem.
Greetings to everyone!
As I found in documentation ActiveRecord shall support non-native types.
I tried create a new "Route" model and then migrate, but I got this:
$ rails g model Route note:text route:path
...
$ rake db:migrate
undefined method `path' for #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::TableDefinition
...
Maybe I missed something?
PostgresQL - 9.2.4, gem 'pg' - 0.15.0
Please forgive me for my weird english.
Cheers.
ActiveRecord only supports the common native types for generated migrations. These types are hardcoded as:
%w( string text integer float decimal datetime timestamp time date binary boolean)
It also supports a few 'virtual' helper types: timestamps and references
You can, however, generate the column as something else (say, integer) and then modify the generated code to look like this:
create_table :routes do |t|
t.text :note
t.column :route, :path
end
According to this, it is now available.
All geometric types, with the exception of points are mapped to normal text. A point is casted to an array containing x and y coordinates.
I can confirm that I was able to create a model with a path type. The path is converted to a string in Rails but saved as a path in your PostgreSQL database.
Since Rails 5 you can use specific geometric data type commands when you run your migrations, so now you can use
t.path :coordinates
instead of
t.column :coordinates, :path
assuming you are inside of your create_table block
You can see all the available options in the PostgreSQL adapter file.
Find more details about Geometric Types (point, line, lseg, box, path, polygon, circle) and Geometric Functions (intersects?, contains?, distance between, etc) in official PostgreSQL docs (currently in version 10.5).
If you need more powerfull functions and proccesing over spatial data, try the Active Record PostGIS adapter gem.