Ranked Model getting started - ruby-on-rails

I'm trying to use the gem 'ranked-model' in Rails 3.2.
This is the model:
class Costproject < ActiveRecord::Base
include RankedModel
scope :active, where("coststatus_id IN (?)", [2, 3, 4, 5, 6] ).where("project_year = ?", Time.now.year + 1)
ranks :row_order,
:scope => :active
I ran this in the Rails console:
Costproject.rank(:row_order).all
After, the column row_order is blank in all the records.
What am I doing wrong?
Thanks for the help!
UPDATE1
I believe now that Costproject.rank(:row_order).all is used to list the projects. I thought it was a command to seed the numbers in the list. Maybe I don't have to do that?

Per our conversation via comments. The problem looks like you need to seed your database before you can use the rank command.
So you can seed your dev database a few ways, via rails console, using your app or modifying your seeds.rb file.
I'm going to suggest you use your seeds.rb file because it's idempotent ( http://en.wikipedia.org/wiki/Idempotence )
So open db/seeds.rb or create one if you don't have one.
Create a few records:
Costproject.create(rank_order: 3, coststatus_id: 2, project_year: 2016)
Costproject.create(rank_order: 2, coststatus_id: 2, project_year: 2016)
Costproject.create(rank_order: 1, coststatus_id: 2, project_year: 2016)
This will insert 3 records into costprojects table. You MUST have the coststatus_id and project_year set to those values per your scope. These won't work:
Costproject.create(rank_order: 10)
Costproject.create(rank_order: 20, coststatus_id: 10)
Costproject.create(rank_order: 30, coststatus_id: 2, project_year: 2013)
then via terminal you can run:
bundle exec rake db:seed
This rake task will run your seed file as if you were manually typing it in your rails console.
Now you should be able to do Costproject.rank(:row_order).all. The first model should have an id of 3, assuming you ran your seed file on an empty database.
For more info:
What is the best way to seed a database in Rails?
http://railscasts.com/episodes/179-seed-data
http://www.jasonwieringa.com/rake_rails_and_databases/

Related

ArgumentError (wrong number of arguments (given 1, expected 2)) when using includes() and where() in Rails

I'm trying to debug an issue in Rails 5.1.5, Postgres 2.1.3. This query works fine in my production environment, but when I copy the database locally and try to do the same thing, I get this error:
Author.includes(:books).where({books: {id: 1}})
ArgumentError (wrong number of arguments (given 1, expected 2))
Every other query I've tried works, and all of the data/versions I've checked seem the same. This also fails if there are no authors at all in the database.
The relationship is set up like this in the Author model
has_many :books, dependent: :destroy
I've tried dropping the database entirely, recreating it from scratch, etc.
Does anyone have any ideas where to dig in from here?
In the Rails documentation for includes, you'll see how it works here
User.includes(:posts).where('posts.name = ?', 'example')
So, when rails yells at you
ArgumentError (wrong number of arguments (given 1, expected 2))
It's might be expecting you to give it
Author.includes(:books).where("books.id = ?", 1)
That doesn't make a ton of sense to me (because your syntax should work), but that was the first thing that came to mind when you got the "it requires 2 params", because in older versions of Rails, that's how it worked.
Some other options might include using SpawnMethod#merge (my favorite):
Author.joins(:books).merge(Book.where(id: 1))
Which essentially performs a left join using ActiveRelation to combine the two queries into a single sql query.
Is this over nested? Or do you have existing scopes?
Author.includes(:books).where(books: {id: 1})
instead of
Author.includes(:books).where({books: {id: 1}})
This is rails 5 syntax, if you are using rails 5.

What is the best way to implement update counter in Ecto/Phoenix?

In ruby on rails(active record) we can update the counter just by calling
update_counter method. for example in rails you just need to write:
# For the Post with id of 5, decrement the comment_count by 1, and
# increment the action_count by 1
Post.update_counters 5, :comment_count => -1, :action_count => 1
# Executes the following SQL:
# UPDATE posts
# SET comment_count = comment_count - 1,
# action_count = action_count + 1
# WHERE id = 5
Is there any easy way to do this in elixir/phoenix considering I have to update the counter of multiple columns?
Alternativaly you can go with something like this using the inc option:
Post
|> where(id: 5)
|> Repo.update_all(inc: [comment_count: -1, action_count: 1])
I wrote this article almost a year ago now, but it's still relevant, and as a bonus, it's written from the perspective of "coming from Rails".
https://medium.com/#lukerollans_17079/counter-caching-in-phoenix-8ac372e5c0c5
Your best bet is to use prepare_changes/2 which provides a mechanism to run an arbitrary function in the same transaction. This allows you to do stuff like counter caching, or whatever you like.
It's also computed at the same time as generating your changeset, so you don't need to "specially" update counters at an arbitrary point in your codebase.

Confusing difference between `count` and `size`

I have a has_many :through relationship between Product and Order:
So I create a new #order and assign it a product like so:
#order = Order.new(products: [my_product])
This manifest in the console like so:
>> #order.products
=> #<ActiveRecord::Associations::CollectionProxy [#<Product id: 145, title: "Some Product" ...>]>
No for some reason I don't understand I get the following results:
>> #order.products.count
=> 0
>> #order.products.to_a.count
=> 1
>> #order.products.size
=> 1
>> #order.products.count
=> 0
I am going to use the size method now, since I want to know how many product I have. But I would have expected that size and count would return the same result for any type of collection.
Check this documentation out on size for Rails: Rails ActiveRecord Size Documentation
Also the documentation for count is here as well: Rails ActiveRecord Count Documentation
There are Ruby AND ActiveRecord methods length, size, and count which are completely different from each other.
Your first example of:>> #order.products.count is attempting to call the Rails ActiveRecord count method (counting records in the DB) while your other example of >> #order.products.to_a.count is attempting to call the Ruby count method (counting items in the container within memory with no connection to the DB).
So to answer your question when using the >> #order = Order.new(products: [my_product]) you are only creating the object in memory and not within the DB. You can read the documentation on size I posted a link to above to tell you why it is able to tell you either the length of the collection or the count of records in the DB depending on the context of its use.
Hope this helps!
size is the in-memory size of the products collection. You'll see when you run that method there is no sql query in the logs. However, if you run count, you'll see it actually produces a sql query (try this in rails console) and since this order is not persisted, you're getting back 0.
Which one should you use? Whichever you consider the source of truth based on where the lifecycle of the object is.

Efficient way to randomize data model in Rails

Creating a programming schedule based on videos in object model.
I want to run a task every day to shuffle this model so the programming each day would be different.
I am aware of
product.shuffle.all for ex. but I want the order to be saved one time each day to do so vs on each server call.
I am thinking to add an attribute to each product, named order which would be an integer to order by. How would I shuffle just product.order for all products in this case?
Would this be the most efficient way? Thanks for the help!
You could use the random parameter of shuffle. It allows for stable randomization:
# When the Random object's seed is different, multiple runs result in different outcome:
pry(main)> [1,2,3,4,5,6,7].shuffle(random: Random.new)
=> [5, 6, 3, 4, 1, 7, 2]
pry(main)> [1,2,3,4,5,6,7].shuffle(random: Random.new)
=> [1, 7, 6, 4, 5, 3, 2]
# When the Random object is created with the same seed, multiple runs return the same result:
pry(main)> [1,2,3,4,5,6,7].shuffle(random: Random.new(1))
=> [7, 3, 2, 1, 5, 4, 6]
pry(main)> [1,2,3,4,5,6,7].shuffle(random: Random.new(1))
=> [7, 3, 2, 1, 5, 4, 6]
By basing the seed e.g. on the number of day in the year you can determine when the results randomization changes. You can (obviously) restore the randomization for any given day if you need to do so.
What I think you want to do would be best solved with a combination of the gem paper_trail along with your product.shuffle.all and an update_attributes call to the DB. That way you can view past versions as they are updated in your DB.

Set Rules in Seeds.rb in Rails

all. I'm currently adding to my seeds.rb file in Rails using the faker gem. I'm wondering: how do you get the fake data to follow "the rules" I want?
I'm building a basketball statistics application. I want stat in seeds to create 300 sets of statistics where all the criteria I have set in the stat model are true. Right now, only 7-9 of the 300 sets of data end up being created. Is there a way to get seeds to ignore the models that don't work and make 300 that do?
For instance, I want field goal attempts (fga in my db) to be greater or equal to field goals made (fg). (I have this "rule" set up in my model.) When I do this in my seeds file:
# seeds.rb snippet
300.times do
stat = Stat.create(
fg: Faker::Number.between(0, 15),
fga: Faker::Number.between(0, 20)
# more stats below
)
how do I make sure that fga is >= fg every time?
Do I have to say specifically in seeds that fg can't be greater than fga? Or do I set a method in my stat.rb model file and Faker will follow it? (I have a few other rules on my model, otherwise I would just set the fake numbers differently.)
Thanks
until Stat.count >= 300 do
Stat.create(
fg: Faker::Number.between(0, 15),
fga: Faker::Number.between(0, 20)
# more stats below
)
end

Resources