Rails 4.2.5 and will_paginate 3.1.0.
I was stuck for some time being unable to do mass operations (like update_all) with will_paginate, and while investigating I've found some strange behavior. Could anyone please explain the reason behind it?
Let's say I have 22 users in the database and per_page = 10:
User.all.page(3) will return correct users (user 21 and user 22),
however:
User.all.page(3).count # => 22
while
User.all.offset(2 * User.per_page).limit(User.per_page).count # => 2
The specific problem I was dealing with is that if I do something like this:
User.all.page(3).update_all(flagged: true)
I get the first page updated (users 1-10) and not the third one (users 21-22).
Is there a way to use will_paginate page method inside a controller to manipulate records within the specific page only?
Update:
The funny thing is that even with .offset().limit() mass update still won't work and I get the same results: the first page is updated instead of the last one (users 1-10, and not 21-22).
So while
User.all.offset(2 * User.per_page).limit(User.per_page).count # => 2
the User.all.offset(2 * User.per_page).limit(User.per_page).update_all(flagged: true) still updates the first 10 users and not the last 2.
The only way I came up with so far is to do User.all.page(3).each { |user| user.update(flagged: true) } which works fine but seems to be terribly ineffective.
Try to add .per_page(10) to your active record query
Related
I am using pagy. I combined two models into one, and I used pagy on that combined model. I am getting this error:
undefined method `offset' for #<Array:0x00007f886f88b3b0>
With the last line of the code below highlighted.
My code:
#problems = Problem.me_and_friends(current_user)
#activities = Activity.me_and_friends(current_user)
#combine = (#problems + #activities).sort{|a,b| a.created_at <=> b.created_at }
#pagy, #combined = pagy_countless(#combine, items:100, link_extra: 'class="" style="color:black; margin:3px;"')
It worked fine with using pagination on #problems alone.
I'd appreciate any help.
As soon as you call the (#problems + #activities), you transform the ActiveRecord::Relation into an array (which is also not good because you are loading all the database rows into memory, sorting and then paginating them). Pagy expects an ActiveRecord::Relation to work, hence the error.
You can consider multiple solutions,
Change your UI to show problems and activities in separate UIs, then you can paginate them separately
Update your models to store both problems and activities in the same table (maybe just a reference table which points to either a Problem or an Activity)
If either of these is not feasible, you can consider rolling out a custom solution for the pagination, but it will be tricky.
Update: June 21, 2021
If you are using Rails 6, it introduces the concept of Delegated Types which fits well into this scenario. The example given in the link mentions the issue of pagination across different tables.
I've been messing around with the Youtube_It gem for the past couple of days as I'm trying to integrate it into a Rails 4 app I'm currently working on.
When I run a search query with it, it outputs an array with a ton of results. As long as I'm in the Rails console, there's no problem with manipulating it. A brief example :
require 'youtube_it'
client = YouTubeIt::Client.new(:dev_key => "dev_key")
data = client.videos_by(:query => "penguin")
data.videos.each { |v| puts v.unique_id }
This outputs a nice, tidy list of all the unique id's that were returned from the query.
When I try to do something similar within a view (I know it shouldn't really be in the view, it's simply there for testing at this point) it just outputs a huge jumbled list of what appears to be XML. This only seems to happen when I try to iterate using .each.
When I do something like :
<% data = client.videos_by(:query => "penguin") %>
<%= data.videos[1].unique_id %>
This returns exactly what I was expecting, one unique_id from the index that I chose. Great! But how do I get ALL the unique id's?
That's where I'm stuck and would really appreciate some help! :)
OK, two reasons (working from the gist you gave me on IRC, located here):
1) You are not actually using the same code as in the console. Your console uses puts unique_id which will print the value of the unique ID, but you are just using unique_id which will get the ID... and then do nothing with it. What you want is probably something like data.videos.map(&:unique_id) (or data.videos.map { |v| v.unique_id } in long form) which will return you an array of the IDs.
2) You are using <%=, which means 'evaluate this ruby line and output the return value onto the page'. The return value of an each statement is the object you called each on - ie. data.videos, so that is what is getting printed out.
I want to count the number of visits on my blog? Can someone please suggest the overall method to implement this feature?
It is just an idea. You can add a count_view column in the database into blogs table with default value 0.
And in the show action of BlogsController add the following code
def show
#blog = Blog.where('id = ?', params[:id]).first
#blog.update_column('count_view', #blog.count_view + 1) if #blog.present?
end
You can modify this logic as per your requirement.
You can check the hit counter gem or the impressionist gem.
You could also use an existing (free) analytics solutions if you want to get much more data than the number of times the action was called (please note that if the same user refreshes the browser 5 times, you get 5 hits):
http://www.google.com/analytics/
Using these you can get data like unique visitors, referral URL, locations data, browser, OS, and a lot of different stuff to make informed decisions. There are several other options (paid, free, real time) available as well:
https://mixpanel.com
https://www.kissmetrics.com/
I have a problem to paginate the record that I request from other web service to get data. When i make a request i get some data(not all because if i get all it will be too big) and the total number of records. will_paginate seem can only display the first page and from the second page it show nothing.
page = params[:page]? params[:page]:1
#fields = ConflictCase.get_fields
sites = ConflictCase.get_paging_sites_from_service(10, (page.to_i - 1)) #this will request data from other webservice that I limit only 10 records
#conflict_cases = ConflictCase.transform(sites["sites"], #fields)
#conflict_cases = #conflict_cases.paginate(:page => page, :per_page => 10, :total_entries => sites["total"].to_i)
The problem is that i always get only 10 records so it can display on the first page but from the second page it show nothing. I though because will paginate will work on it own to ignore the first 10 records when we move to second page or more.
Have anyone can suggest any idea?
Thank for your help
This is a perfect scenario to use the ruby debugger, or spit out to the logger the values during each iteration of your objects.
Firstly I would assume will_paginate isn't the issue, so I would debug to look at the #conflict_cases object and what is being passed into the paginate() function, and the values each time for page and sites['total'].
I have a Rails 3 app that has several hundred records in a mySQL-DB that need to be updated multiple times each hour. The actual updating is done through delayed_job which is triggered in controller-logic (checking if enough time has passed since the last update, only then sth. happens).
Each update is slow, it can take up to a second in some cases (although it averages at 3 - 5 updates/sec.).
Code looks like this:
class Thing < ActiveRecord::Base
...
def self.scheduled_update
Thing.all.each do |t|
...
t.some_property = new_value
t.save
end
end
end
I've observed that the execution stalls after 300 - 400 records and then the delayed job just seems to hang and times out eventually (entries in delayed_job.log). After a while the next one starts, also fails, and so forth, so not all records get updated.
What is the proper way to do this?
How does Rails handle database-connections when used like that? Could it be some timeout issue that is not detected/handled properly?
There must be a default way to do this, but couldn't find anything so far..
Any help is appreciated.
Another options is update_all.
Rails is a bad choice for mass data records. See if you can create a sql stored procedure or some other way that would avoid active record.
Use object.save_with_validation(false) if you are ok with skipping validations altogether.
When finding records, use :select => 'a,b,c,other_fields' to limit the fields you want ('a', 'b', 'c' and 'other' in this example).
Use :include for eager loading when you are initially selecting and joining across multiple tables.
So I solved my problem.
There was some issue with the rails-version I was using (3.0.3), the Timeout was caused by some bug I suspect. Updating to a later version of the 3.0.x branch solved it and everything runs perfectly now.