removing duplicate entry for csv import in ruby - ruby

while importing csv row i need to check wether this is duplicate entry or new entry.
my csv looks like this,
company,location,region,service,price,duration,disabled
Google,Berlin,EU,Design with HTML/CSS,120,30,false
Google,San Francisco,US,Design with HTML/CSS,120,30,false
Google,San Francisco,US,Restful API design,1500,120,false
Apple,London,EU,Design with HTML/CSS,120,30,false
Google,Berlin,EU,Design with HTML/CSS,120,30,false
Google,San Francisco,US,Restful API design,1500,120,false
Also the row value should be imported in different table whose association is like this
A Company:
can have multiple regions: US, EU and each region multiple branches, i.e. London, Berlin. Define a hierarchy to represent this logic.
has many Services. If there are more branches, they will all share the same services
can be disabled
A Service:
has a duration
has a price
can be disabled
if the company is disabled, all services are disabled.
for which i have implemented association like this
class Company < ApplicationRecord
has_many :regions
has_many :services
has_many :locations, through: :regions
end
class Region < ApplicationRecord
belongs_to :company
has_many :locations
end
class Location < ApplicationRecord
belongs_to :region
belongs_to :company
end
class Service < ApplicationRecord
belongs_to :company
end
How will I import this?
I am doing something like this
namespace :import do
desc "Import data"
task company: :environment do
CSV.foreach('lib/data/companies_data.csv', headers:true) do |row|
company = Company.create(:name => row["company"])
region = company.regions.create(:name => row["region"])
if region.id and company.id
location = company.locations.create(:name =>row["location"],
:region_id => region.id)
service = company.services.create(:name => row["service"],
:price => row["price"], :duration =>
row["duration"], :disabled =>row["disabled"])
end
end
end
end
How do I check wether a row is already present in database as it already contains associated table.

You can use .first_or_create. This will only create new db records if there is not a match on the previous ActiveRecord Relation call:
Model.where(some_unique_field: row['Unique Column']).first_or_create(row)
You can also pass a block to first_or_create as listed in the docs if you want to apply any additional logic to the CSV row ie model.price = row['price'] + fee

Related

How to join 1:N tables in rails and instead of multiple rows for record get one row with extra column containing array of IDs from joined table

I have 3 models
class Mission < ActiveRecord::Base
belongs_to :guild
end
class Guild < ActiveRecord::Base
has_many :missions
has_many :guild_coordinators, :dependent => :destroy
has_many :coordinators, :through=> :guild_coordinators, :class_name => "Associate"
end
class GuildCoordinator < ActiveRecord::Base
belongs_to :guild
belongs_to :coordinator, :class_name => "Associate"
end
If I do
Mission.joins(:guild => :guild_coordinators)
I get row for every guild -> guild coordinator association
Is it possible to get unique records for Missions with joined Guilds and in one column get IDs of all coordinators in an Array?
edit:
expected result is something like this:
#<ActiveRecord::Relation [#<Mission id: 13, fy: 2018, guild_id: 31, name: "test mission", status: 0, coordinators: [1,2,3,5,8]>
my database is postgres
as output I need Active Record relation for gem ajax-datatables-rails
With Postgresql you can use array_agg aggregate function:
Mission.
joins(guild: :guild_coordinators).
select('missions.*, array_agg(guild_coordinators.id) as coordinators').
group(:id)
And you get exactly ActiveRecord::Relation, which will contain(after call) Mission objects with additional field coordinators:Array.
The second option is to use .includes like my or #garrett-motzner comments show.

How to use Rails include?

I have a model user with many orders
class User < ApplicationRecord
has_many :orders, inverse_of: :user, dependent: restrict_with_exception
end
and a model order as follows :-
Class Order < ApplicationRecord
belongs_to :user, inverse_of: :order
end
I want to fetch all orders but with details of user like user.name and user.mobile in same set. How do I use include in this case?
You can use includes using the below mentioned query:
#users = User.where(id: 1).includes(:orders)
then iterate over #users and fetch the corresponding user and order data.
Also, you could use lazy loading as well using the below query:
#users = User.where(id: 3).joins(:orders => [:order_data]).select("orders.*, users.first_name")
In this you will be getting all the data in the single query without rails caching the db objects in memory as in the case of includes.

ActiveRecord get all + associated details

I am trying to retrieve a list of all tasks, where each task has a developer and reviewer. I am able to retrieve the list but it contains developer_id and reviewer_id. How do I retrieve a list containing developer name and retriever name?
class Person < ActiveRecord::Base
end
class Unread_Object < ActiveRecord::Base
belongs_to :person
end
class Developer < Person
has_many :tasks
end
class Reviewer < Person
has_many :tasks
has_many :unread_objects
end
class Task < ActiveRecord::Base
belongs_to :developer
belongs_to :reviewer
has_many :documents
after_save :add_task_to_unread_objects
protected
def add_task_to_unread_objects
Person.find_each do |person|
Unread_Object.create(
:person_id => person.id,
:internal_object_id => self.internal_object_id,
:unread_cause => 'Create')
end
end
end
Things I have tried.
get '/taskslist' do
#Task.includes([:developer, :reviewer]).all.to_json
#Task.joins(:developer,:reviewer).select("tasks.*, people.*").to_json #works somewhat but only shows one name
#Task.includes(:reviewer.name,:developer.name).all.to_json #"undefined method `name' for :reviewer:Symbol"
#Task.find(:all, :include => {:people => :name}).to_json #Couldn't find all Tasks with 'id': (all, {:include=>{:people=>:name}})
end
I hope to get Tasks json with nested json for developer, reviewer and other objects.
This question is follow up of this.
After some searching found as_json(include: <association>)
So this works
Task.includes(:developer,:reviewer).all.as_json(include: [:developer,:reviewer]).to_json
But other alternatives need to be seen.

Many to many and one to many association between same models

I am creating a simple Sinatra app, using Sequel for my ORM.
Most of the data revolves around users and events where:
An event can have many users, one of which is the "owner".
Users can have many events, one or many of which they "own".
Here is a simplified version of my schema/model definitions:
class User < Sequel::Model(:users)
many_to_many :events
one_to_one :event
end
class Event < Sequel::Model(:events)
many_to_many :users
many_to_one :user
end
# provides a link between users and events
# e.g. event.users or user.events
# I am unsure how necessary this is :)
db.create_table :events_users do
primay_key :id
foreign_key :event_id, :events
foreign_key :user_id, :users
end
This allows me to get the users attached to an event, or the events that a user is attached to, but I am struggling to express the "ownership" of an event. It seems like the following pseudocode would work:
my_user = User.all.first
owned_events = Event.where(user_id = my_user.user_id)
That leads to two questions:
Does the current way i'm using assocations make sense?
How do I express ownership of an event in terms of Sequel's association model?
Maybe something like this:
class Event
many_to_one :owner, :class=>:User
many_to_many :users
end
class User
one_to_many :owned_events, :class=>:Event, :key=>:owner_id
many_to_many :events
end
You'll need to add owned_id field in events table.
Usage:
user = User.all.first
event = Event.new(:title => 'New Event')
events.add_owner(user)
event.save
another_user = User.create(:name => 'Jack')
event.add_user(another_user)

has_and_belongs_to_many model creation needed?

I have orders and items table. I also have a third table called orders_items. Which I learned on creating from the following link (2nd graph) http://www.tutorialspoint.com/ruby-on-rails/rails-models.htm
models/order.rb
class Order < ActiveRecord::Base
has_and_belongs_to_many :items, through: :item_order
end
models/item.rb
class Item < ActiveRecord::Base
has_and_belongs_to_many :orders, through: :item_order
end
[orders_items] table has the following:
integer :order_id
integer :item_id
Do I have to create a models/order_item.rb file to add:
belongs_to :order
belongs_to :item
If so what is the correct naming format that it should be?
Would the name for the model file [order_item.rb] correct to distinguish which table it refers to?
models/order_item.rb ??
class OrdersItem ??? < ActiveRecord::Base
belongs_to :order
belongs_to :item
end
From the API
The join table should not have a primary key or a model associated
with it. You must manually generate the join table with a migration
such as this
class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
def change
create_table :developers_projects, id: false do |t|
t.integer :developer_id
t.integer :project_id
end
end
end
Specifies a many-to-many relationship with another class. This
associates two classes via an intermediate join table. Unless the join
table is explicitly specified as an option, it is guessed using the
lexical order of the class names. So a join between Developer and
Project will give the default join table name of “developers_projects”
because “D” precedes “P” alphabetically
In your case the join table name should be items_orders.
Your model must be named OrderItem. And you don't need belongs_to in this class. The file name (order_item.rb) is correct.
I think you need this relationship to fulfill your needs, except if orders is an item too
class Order < ActiveRecord::Base
has_many :items
end
and
class Item < ActiveRecord::Base
belongs_to :order
end

Resources