How to use offset and limit for inserting data in database - ruby-on-rails

I am learning Ruby on Rails and SQlite. I saw some interesting code for the seed file while I was looking at ways around to create a seed file:
Classroom.all.each_with_index do |classroom, i|
classroom.students << [Student.limit(8).offset(i*2)]
end
I understand that it is inserting students in the classroom but don't understand what limit and offset are doing.
I tried to search online for this and found https://apidock.com/rails/ActiveRecord/QueryMethods/offset but it didn't make anything clear to me.
Any suggestion for the resources where I can find more info on this or any example that can help me to understand this?

Sure (see http://guides.rubyonrails.org/active_record_querying.html for details)
Student means a SQL query to get all the rows from the Student table.
What each of these methods like limit and offset are doing is modifying the underlying SQL query that Rails is building.
The limit(8) means just get 8 items.
The offset(i*2) means start taking them i*2 elements down the list.
If it was just an array (and not a database table) it be like saying
student[i*2..i*2+8-1]
Note I wonder if this code has a bug in it? It would make more sense to be offset(i*8) . Then this code would take groups of 8 students and put them in different classes.
As it is this will take the first 8 students, put them in the first classroom, then take students 3-10 and putting them in the next class, etc, so some students will end up in up to 4 different classes!

Related

Join an ActiveRecord model to a table in another schema with no model

I need to join an ActiveRecord model in my Ruby on Rails app to another table in a different schema that has no model. I've searched for the answer, and found parts of it, but not a whole solution in one place, hence this question.
I have Vehicle model, with many millions of rows.
I have a table (reload_cars) in another schema (temp_cars) in the same database, with a few million records. This is an ad hoc table, to be used for one ad hoc data update, and will never be used again. There is no model associated with that table.
I initially was lazy and selected all the reload_cars records into an array (reload_vins) in one query, and then in a second query did something like:
`Vehicle.where(vin_status: :invalid).where('vin in (?)', reload_vins)`.
That's simplified a bit from the actual query, but demonstrates the join I need. In other queries, I need full sets of inner and outer joins between these tables. I also need to put various selection criteria on the model table and/or the non-model table in various steps.
That blunt approach worked fine in development, but did not scale up to the production database. I thought it would take a few minutes, which is plenty fast enough for a one-time operation. But, it timed out, particularly when looping through sets of records. Small tweaks did not help.
So, I need to do a legit join.
In retrospect, the answer seems pretty obvious. This query ran pretty much instantly, and gave the exact expected result, with various criteria on each table.
Here is one such query:
Vehicle.where(vin_status: :invalid)
.joins("
join temp_cars.reload_cars tcar
on tcar.vin = vehicles.vin
where tcar.registration_id is not null
")

ROR / Database: How to create a custom order list for database records?

I have a database table with some articles (for a website) like so:
Articles:
id title order_id
1 - 1
2 - 4
3 - 3
4 - 2
Now on the webpage I want to use the order_id to order the articles, this works perfectly fine, using ROR active record.
However when I want to update the order_id I would have to update all of the records using this technique, each time a change to the order_id is made. What is a better way of doing this ?
Thanks
You want acts_as_list:
class Article < ActiveRecord::Base
acts_as_list :column => 'order_id'
end
There's no way around updating lots of records when you perform a reordering, but acts_as_list can do all that for you with methods like Article#move_to_top and Article#move_lower.
There are some gems to solve your problem. The Ruby Toolbox has them in the category Active Record Sortables. As the time of writing (March 2017) the top gems in this list are:
act_as_list (Website, GitHub)
This is the most popular choice for managing an ordered list in the database and it is still maintained 10 years after its creation. It will do just what you wanted and manage the numbers of the items. The gem will keep your position field numbers form 1 to n in the correct order. This however means that inserting items in the middle of the list means increasing all of the position values for the list items below it, which can be quite some work for your database.
ranked-model (GitHub)
This gem also manages custom ordered lists for you. However it uses another approach behind the scenes, where your list items get position numbers big and spaced apart across the full range of integer values. This should get you performance benefits if you have large lists and need to reorder the items often. It seems to me that this gem might no longer be maintained though, since the author is now doing Ember.js development, it should work though. Edit: It is still maintained.
sortable (GitHub)
This seems to be the same like act_as_list but with the ability to put your items into multiple list. I'm not really sure if this is a valid use-case since you could just create multiple items. It looks like it was not maintained for a long time and not used by many.
resort (GitHub)
This gem uses a linked list approach, i.e. every database entry gets a pointer to the next entry. This might be a good idea if you need a lot of inserts in the middle of your lists, but seems like a terrible idea for just getting the list of entires or if something goes wrong in the database and the chain breaks. It is quite new, so let's see how it develops.
acts_as_restful_list (GitHub)
This gem is "Just like acts_as_list, but restful". It seems to aim for a nicer API. The company behind it does no longer exist, so I'd rather use act_as_list and deal with its API, which is not too bad anyway.

Is it possible to alter a record in rails, without first reading it

I want to alter a record, but I don't want to read it out of the database first, because frankly I don't see the point. It's huge and across a network that is slow and expensive.
Can it be done (easily)?
Lets say I have a record with 100 fields (for arguments sake) and I want to alter one field in the table. I have a really bad connection to the database (this is true) because it's housed on a different box and there's nothing I can do to change this.
Right now I pull down the record and rails validates its contents (because I have serialized bits) I then alter one field (one of the hundred depending on X condition) and save the record again. Which I suppose writes the whole record to the database again, with no knowledge of the fact that I only changed one small bit. (this last bit is assumption)
Now to change one record it's sending a huge amount of data across the network, and it could be that I'm only changing one small small thing..
Also it's doing two queries on the database. First the select * then the update..
So my question.. are there smarter base classes that do this right, to write without read?
Top of my head I would think a setter method for each field with a bool flag for changed.
When saving, walk the flags and where true... Does this happen now, if so how do I make use of it?
Rails models have the update method, which does a SQL select then an SQL update.
Its use is simple (suppose you have a model named Person)
Person.update(person_id, :user_name => 'New Name')
The drawback is that you have to know beforehand the person id.
But then, you will always have to do a query to find out that. You could write your own SQL to change the column value, with a WHERE clause that searches for the param you have.
Rails models have the update_all method, which does only a SQL update without loading the data.
But I wouldn't recommend using it because it doesn't trigger any callbacks or validations that your model may have.
You could use the update_all like this:
Book.update_all "author = 'David'", "title LIKE '%Rails%'"
ps: examples were all taken from the Rails official documentation. If you search for update, or update_all, you'll find both methods in no time.
Take a look there, it's a good place to find out what rails can do.
Rails API link
It's not obvious from the documentation, but update_all is the answer to this question.
Book.where(id: 123).update_all(title: "War and Peace")
results in exactly one query:
UPDATE `books` SET `books`.`title` = "War and Peace" WHERE `books`.`id` = 123
It's been a while since this question was asked, but this is so for Rails 4/5/6.

Ruby dynamically tied to table

I've got a huge monster of a database (Okay that's not quite true, but there are over 8 million records in one product table)..
This table is fed by 13 suppliers.
Even with the best indexing I could come up with, searching for the top 10,000 records that are ready for supplier 8, is crazy slow.
What I'd like to do is create a product table for each supplier and parse the table into smaller tables.
Now in c++ or what have you, I'd just switch the table that I'm working with inside the class.
In ruby, it seems I'll have to create a new class for each table, and do a migration.
Also as I plan to have some in session tables #, I'd be interested in getting ruby to work with them..
Oh.. 8 million and set to grow to 20 million in the next 6 months.
A question posed, was what's my db engine.. Right now it's sql, but I'm open to pushing my db to another engine, if it will mean I can use temp tables, and "partitioned" tables.
One additional point to indexing.. Indexing on fields that change frequently isn't practical. Like price and quantity.. I'd have to re-index the changed items, each time I made a change.
By Ruby, I am assuming you mean that inheriting from the ActiveRecord::Base class in a Ruby on Rails application. By convention, you are correct in that each class is meant to represent a separate table.
You can easily execute arbitrary SQL using the "ActiveRecord::Base.connection.execute" method, and passing a string that is your SQL query. This would bypass having to create separate Ruby classes that would represent transient tables. This is not the "Rails approach", however it does address your question of allowing switching of the tables inside a class file.
More information on ActiveRecord database statements can be found here: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html
However, as other people have pointed out, you should be able to optimize your query such that splitting across multiple tables is not necessary. You may want to analyze your SQL query's execution plan using various tools to optimize the execution. If you are using MySQL view check out their query execution planning functionality: http://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html
By introducing indexes, or changing join methods between tables, etc you should be able to return reduce your query execution time.

Wrapping my head around MongoDB, mongomapper and joins

I'm new to MongoDB and I've used RDBMS for years.
Anyway, let's say I have the following collections:
Realtors
many :bookmarks
key :name
Houses
key :address, String
key :bathrooms, Integer
Properties
key :address, String
key :landtype, String
Bookmark
key :notes
I want a Realtor to be able to bookmark a House and/or a Property. Notice that Houses and Properties are stand-alone and have no idea about Realtors or Bookmarks. I want the Bookmark to be sort of like a "join table" in MySQL.
The Houses/Properties come from a different source so they can't be modified.
I would like to be able to do this in Rails:
r = Realtor.first
r.bookmarks would give me:
House1
House2
PropertyABC
PropertyOO1
etc...
There will be thousands of Houses and Properties.
I realize that this is what RDBMS were made for. But there are several reasons why I am using MongoDB so I would like to make this work.
Any suggestions on how to do something like this would be appreciated.
Thanks!
OK, first things first. You've structured your data as if this were an RDBMS. You've even run off and created a "join table" as if such a thing were useful in Mongo.
The short answer to your question is that you're probably going to have re-define "first" to load the given "Bookmarks". Either "server-side" with an $in clause or "client-side" with a big for loop.
So two Big Questions about the data:
If Bookmarks completely belong to a Realtor, why are they in their own collection?
If Realtors can Bookmark Houses and Property, then why are these in different collections? Isn't this needless complication? If you want something like Realtor.first on bookmarks why put them in different collections?
The Realtors collection should probably be composed of items that look like this:
{"name":"John", "bookmarks": [
{"h":"House1","notes":[{"Nice location","High Ask"}] },
{"p":"PropertyABC","notes":[{"Haunted"}] }
] }
Note how I've differentiated "h" and "p" for ID of the house and ID of the property? If you take my next suggestion you won't need even that.
Taking this one step further, you probably want Houses and Properties in the same collection, say "Locations". In the "Locations" collection, you're just going to stuff all Houses and Properties and mark them with "type":"house" or "type":"property". Then you'll index on the "type" field.
Why? Because now when you write the "first" method, your query is pretty easy. All you do is loop through "bookmarks" and grab the appropriate key ("House1", "PropertyABC") from the "Locations" collection. Paging is straight forward, you query for 10 items and then return.
I know that at some level it seems kind of lame."Why am I writing a for loop to grab data? I tried to stop doing that 15 years ago!" But Mongo is a "document-oriented" store, so it's optimized for loading individual documents. You're trying to load a bunch of documents, so you have to jump through this little hoop.
Fortunately, it's not all bad. Mongo is really fast at loading individual docs. Running a query to fetch 10 items at once is still going to be very quick.

Resources