ruby on rails find.all where and append results to different model - ruby-on-rails

OK, so I have a table of data called "Projects" where I have an ID and a name. Let's say its in the world of zillions of objects and I'm not allowed to add any relationships to it, or columns, indexes or anything like that. I want to work with a specific set of these projects that has "TI" as the seventh and eighth digit of the name, and I want to store them in another model called TI Projects where there is an ID and name column as well, so I can create relationships, add columns, etc.
So, what I want to do is find all Projects where the 7th and 8th digit of name are TI, and then I want to insert those that are found in to the TI Projects model where name is carried over from Projects to TI Projects model. I'm having a hard time with this, obviously. I'm doing
#tiprojects = Projects.all(:conditions => { :name => %%%%%%TI% } )
#tiprojects.create

Related

Why does `has_one` in rails require a foreign key?

Consider two tables Foo and Bar and consider models based on them. Now consider a one-to-one relationship between them.
Foo contains has_one :bar in it's declaration so that we're able to access Bar from Foo's objects. But then what I don't understand is why Bar needs a foreign key referencing Foo?
Shouldn't it be easier if they just compare both the ids to get the result?
I'm assuming that there will be problems with comparing both ids and I want to know what the problems are.
The problem with ids is that they store auto-incremented values. Let's consider 2 tables students and projects.
Let's assume a student can have at most 1 project. Which means he can either have a project or not.
Now consider 2 students A & B.
students table
id name
1 A
2 B
now projects table
id name
1 P1
2 NULL
in this case A has a project named as P1 but B doesn't and we're creating a null entry just to maintain and match the id of records present in projects with the students but this is not feasible in the long term. If in a school there are 1000 students then we'll have may be 500 empty rows for 500 students who are not working on a project.
That's why adding a column in projects table is a feasible solution to reduce the size of the table and maintain relationships as well and also if you're going to delete a record then the new id won't be same as the previous one as id's are auto-incremented.
now projects table
id name student_id
1 P1 1
is more feasible and flexible as well. You can make it has_many as well because a student can work on multiple projects as well.
I hope this helps you.
You can't assume that the DB engine will add the same IDs to rows in different tables. You can (I would not recommend) make an app with such behavior and implement it with triggers and constraints, but this would be a very creative (in a negative sense) approach to relational databases.

Normalizing issue with data history

I have two entities: Location and Employee. Each employee works in a single location at a time. For any given moment in time, the model is as follows:
There is, however, a requirement to also store historical information for all locations and employees for every end-of-month. I can achieve this by adding a Month PK attribute in both entities, but: how do I handle the relationship in that case?
A foreign key has to reference a composite PK in its entirety. Several alternatives come to mind:
Option 1: repeat the Month attribute in the Employee entity to get the full PK as FK attributes. This feels a bit redundant? If an employee has existed in a given month, surely she has to work in a location in the same month - i.e. the two Month attributes have to always have the exact same value:
Option 2: re-use the Month attribute in the PK of the Employee entity as a foreign key referencing Location. I don't even know if this is allowed (note: I'm going to be using SQL Server eventually, if it matters here)?
Option 3: create a separate bridge entity that holds the history of Location-Employee relationships. This feels kind of neat, but then again I have some doubts as to whether or not I can use one Month attribute here or if I need two of them. Also, it would allow many-to-many relationships (an employee in several locations on a given month), which is not supposed to happen in this case and I'd like to be able to enforce this in the data model.
Am I missing something obvious here? What is the "correct" and properly normalized solution? Or should I just leave the FK constraints out?

Constructing a 1-many relationship with custom string foreign keys in PGSQL ActiveRecord

I have the following tables (Showing only the relevant fields):
lots
history_id
histories
initial_date
updated_date
r_doc_date
l_doc_date
datasheet_finalized_date
users
username
So I am rebuilding an exisiting application that dealt with a rather large amount of bureaucracy, and needs to keep track of five separate dates (as shown in the histories table). The problem that I am having is that I don't know how best to model this in ActiveRecord, historically it's been done by having the histories tables represented as so:
histories
initial_date
updated_date
r_doc_date
l_doc_date
datasheet_finalized_date
username
Where only one of the five date fields could ever be filled at one time...which in my opinion is a terrible way to go about modeling this...
So basically I want to build a unique queryable connection between every date in the histories table and its specific relevant user. Is it possible to use every timestamp in the histories table as a foreign key to query the specific user?
I think that there's a simpler approach to what you're trying to accomplish. It sounds like you want to be able to query each lot and find the 'relevant user' (I am guessing that this refers to the user who did whatever action is necessary to update the specific column on the histories table). To do this I would first create a join table between users and histories, called user_histories:
user_histories
user_id
history_id
I would create a row on this table any time a lot's history is updated and one of the relevant dates changes. But that now brings up the issue of being able to differentiate which specific date-type the user actually changed (since there are five). Instead of using each one as a foreign key (since they wouldn't necessarily be unique) I would recommend creating a 'history_code' on the user_histories table to represent each one of the history date-types (much like how a polymorphic_type is used). Resulting in the user_histories table looking like this:
user_histories
user_id
history_id
history_code
And an example record looking like this:
UserHistory.sample = {
user_id: 1,
history_id: 1,
history_code: "Initial"
}
Allowing you to query the specific user who changed a record in the histories table with the following:
history.user_histories.select { |uhist| hist.history_code == "Initial" }
I would recommend building these longer queries out into model methods, allowing for a faster, cleaner query down the line, for example:
#app/models/history.rb
def initial_user
self.user_histories.select { |uhist| hist.history_code == "Initial" }
end
This should give you the results you want, but should get around the whole issue of the dates not being suitable for foreign keys, since you can't guarantee their uniqueness.

RoR and Relational databases: handling Model default values in database

I'm working on a RoR project for work, and I'm having trouble deciding about the design of my relational database tables.
Consider the following:
I've got a model Product, each product has a unique name.
I've also got a model called Shop, each shop has many products.
Finally, I have an Order model, Order is obviously connected to the shop which the order has been made from, and to the list of products which were ordered.
I would like to keep default values (e.g. default price) for each product, and I'd like each Shop to be able to overwrite those default values if needed, but can't really decide on the strategy of doing so.
What I have in mind is as follows:
Create a Product table, which will include the product name, and also, columns to keep the product's default values (e.g. price)
Create a Shop table, which will include everything which has to do with the shop.
Create a Product_To_Shop table, which will hold the product quantity for that exact shop, and will hold additional columns, which match the Product default values columns which will let the shop overwrite the default product related values.
Now when I'd like to get the price for a specific order, i'll first check out the Product_To_Shop table, for the related Product and Shop, and check the Price field for the matching row, and in case it's not set to a value (nil), head to the Product table and fetch the default price value for the relevant product.
The whole thing looks a bit complex for a task which seems a bit more trivial.
I was wondering if anyone ever had to deal with keeping default values in the database like that and has a more elegant solution, since this one seems like an overkill...
you can do the following
Create a Products table, which will include the products data ( but no prices).
Create a Shops table, which will include the shops data.
Create a Prices table, which will include Product_id, Shop_id, Price.
Shop_id defaulted to null which will indicate your default price
When you need the price get the one matching shop_id or isnull

new records insertion into database table in my case

I am developing a Rails v2.3 application which is a service to search projects' information where projects info are stored in database.
There is an existing projects table in the database like following:
For the sake of satisfying customer’s requirement, this table needs to insert new data in the mid-night everyday.
The reason of creating these new records is to make the Rails application be able to search projects by a single word besides searching by the full name.
For example, if search by word "portal", both Car rental portal and Position track portal records should be found by the Rails application. That's the app.'s database needs to have all the records of each single word from project_name.
So, my plan is to generate those new records by spliting the value in project_name column (of the above projects table) into single words and then use each single word as a new record's project_name while keep other columns of the record unchanged.
For example, in above table, the first record has project_name "Car rental portal", what I gonna do is to split this string into 3 words and construct the following three new records to be inserted into the table:
To achieve this. I tried to make a rake task which gets all records from the original projects table, and for each record, the rake task splits the string value of project_name column into words, then construct the new records with words and insert into the table. My rake task looks like the code below:
all_records = ActiveRecord::Base.execute("select * from projects;")
all_records.each do |record|
user_id = record[0]
project_name=record[1]
department = record[2]
other = record[3]
words=project_name.split()
words.each do |word|
sql = "insert into project values (#{user_id},#{word},#{department},#{other});"
ActiveRecord::Base.execute(sql)
end
end
The rake task works well, it creates the expected new records and inserted into the projects table, BUT the problem is it takes 36 hours to complete!
It is understandable since the origin table is very very large, if split the string to words and create the new record it's like create a 3 times larger table (suppose each string of project_name has 3 words).
My question:
Could some Rails experts suggest me some more efficient way to achieve the new record insertion thing I described above?
Or any new way to enable single word search in my case? (That's do not use the way I designed to have each single word store in the database.)
If you do this only for searching purpose, why don't you use Sunspot ? It supports full text search.
Splitting project name sounds like a really bad idea for me.
But if you want to take it less time, then I'd encourage you to split this single task into more rake tasks, that would do the same, but for other set of projects.
For faster importing, you want to use activerecord-import, it will speed up your execution by a couple orders of magnitude.
columns = [:title, :project_name, :department, :other]
values = all_records.inject([]) do |values_arr, record|
user_id, project_name, department, other = record
project_name.split.each do |name|
values_arr << [user_id, name, department, other]
end
values_arr
end
class TempModel < ActiveRecord::Base; set_table_name "projects"; end
TempModel.import columns, values, :validate=>false

Resources