ActiveAdmin pagination links are gone with scoped_collection group by - ruby-on-rails

I have the following ActiveAdmin model:
ActiveAdmin.register Job do
controller do
def scoped_collection
Job.all
end
end
This works just fine, the pagination and the links. However, I need to use a more complex query to list the count of Job views for each job. So I changed my scoped collection to this:
ActiveAdmin.register Job do
controller do
def scoped_collection
Job.joins('left join jobView on job.Id = jobView.JobId')
.select('job.Id, job.Title, job.CreatedDate, job.DeadLineDate,
job.IsClosed, job.IsPublic, job.IsApproved, count(1) as totalViews')
.group('job.Id, job.Title, job.CreatedDate, job.DeadLineDate,
job.IsClosed, job.IsPublic, job.IsApproved')
end
end
The second works. But the pagination links are not showing anymore. I can even see that the pagination itself works, because if I insert in the browser a query string like '?page=2' it paginates correctly to page 2. The only real problem is the missing links for changing pages on the bottom of the page.
Anyone knows what's going on? Thanks guys.
EDIT
I've found out that the problem happens because, if you do something like:
model = MyModel.select(field1, field2)
model.count
model.count will break because rails is executing a query like
select count(field1, field2) from MyModel
However, count just accepts 1 parameter. And ActiveAdmin paginations probably does a count.
The solution would be to use size instead count. But how to change this behavior in AA?
Edit 2 - Found ugly solution
Since I use a left join in my query, the number of rows will always be equal to the left table count. So, I did a count on my Job table inside my Index Controller and then I passed this count to a partial where I build the pagination links by myself:
/admin/job.rb:
index do
...
#jobsForPagination = Job.all.page(params[:page]).per(8)
render partial: "paginate", locals: {resource: #jobsForPagination}
end
/views/admin/jobs/_paginate.html.erb:
<%= paginate resource %>
8 is the activeadmin config.per_page.
If someone finds a better solution or has any comments, please reply.
Thank you!

Related

How to compare two items within Ruby on Rails?

So I'm trying to re-create GitHub version control for let's say posts. I've found a way to re-create an original post using duplicate AND another method to create a new post based on the original. Cool.
My issue is being able to display both the original and the new on the same page.
What I've attempted thus far is to just rely on the show method with having:
def show
#post = Post.find(params[:id])
end
Then in the view have in the form a checkbox to allow a user to select multiple posts, click a submit, and a new page renders displaying both side by side. Preferably showing the differences between the two but that's a wish list as I deal with this first.
Actually could I just simply do?:
def other_show
#post = Post.where(params[:id])
end
I also added in status as a boolean to help on the view for marking the checkbox. Would I then need to put something in the other_show method about the status?
If you want to "recreate" some sort of version control I suggest you use something like the audited. Instead of building your own. From your example and comments it seems you don't have a clear relation between all related (versions of) posts.
Using this gem, each change to the Post content (for example, if configured properly) would be stored as an audit.
Showing the differences is a different problem. That's usually called a diff and you can find gems that do it for you, for example: diffy
To show 2 different entities on one page you need to give posts_controller both ids.
Declare your show method like this:
def show
#original = Post.find(params[:id])
#compared = Post.find(params[:compared_id])
end
Correct route to this method will look like this:
/posts/:id?compared_id=:another_id
# Example: /posts/1?compared_id=2
To construct such a link in your view, you need to declare link_to method like this:
<%= link_to '1 <> 2', post_path(#post, compared_id: '2') %>
If you want to have a page where user can check 2 checkboxes for certain posts, you'll need to construct such href via Javascript.
But in fact I wouldn't suggest you to modify show method for such a task. It is better to use show method only for showing one entity from database. You can create another method, e.g. compare and pass both parameters there.
def compare
#original = Post.find(params[:original_id])
#compared = Post.find(params[:compared_id])
end
In routes.rb
resources :posts do
get 'compare', on: :collection
end
It will give you helper compare_posts_path, which will lead to /posts/compare and you'll need to pass original_id and compared_id to it, like this:
<%= link_to 'Compare', compare_posts_path(original_id: 'some_id', compared_id: 'some_another_id') %>
It will result to
/posts/compare?original_id=some_id&compared_id=some_another_id

Rails filter product listing based on attribute in controller

Rails newbie here. This specific question has probably been asked before, if not here then on some other site, but after looking around a lot I wasn't able to find anything helpful because I lack the terminology to describe what I want to accomplish. I'm sorry if it comes across as trivial.
Basically I have a freshly created Rails project with a scaffold Item (generated by rails g scaffold Item [...attributes...]) and I want to create an additional page, similar to the index page, but instead of displaying all of the items I want the items to be filtered. So for the index page the part in the controller file looks like this
def index
#items = Item.all
end
and I want to know how to, instead, have some sort of controller for my other page (call it index2) that uses some find-like method only grabs the Items that have a certain attribute, e.g. are "red" in color:
def index2
#items = Item.find(color: "red") #all items that have red as their color attribute
end #are assigned to #items
How can I do this? And where can I find more manipulations (other than all(), first, second, ...) like this? Thank you for your patience.
You can add an action to your ItemsController
def red_items
#items = Item.where(color: "red")
end
you can use where for all the filters
You will have to add a view called red_items.html.erb to /app/views/items for the controller to render automatically. If you want to use index template, then just render the template explicitly in your new action
def red_items
#items = Item.where(color: "red")
render :template => "index"
end
Here is a link to Active Record Query Interface where you can find all possible query methods

Confused on Ruby URL parameters

I have a Questions model that has a number of different fields/parameters. If I want to view all of them, I just go to:
http://localhost:3002/questions
In order to view one specific question, I go to something like
http://localhost:3002/questions/1
How can I view the questions that satisfy a specific parameter requirement? Something like
http://localhost:3002/questions?difficulty=1
just gives the same result as viewing all questions. I know that syntactically I'm way off... but can anyone lead me in the right direction? How can I set this up on the controller-side?
You have to intercept the param in your controller and filter your results using the param.
def index
if params[:difficulty]
#questions = Question.where(difficulty: params[:difficulty])
else
#questions = Question.all
end
end
You can pass parameter depends on your condition
see the example
View:
<%= link_to "View", questions_path(:difficulty => 1) %>
note: you can send dynamic values to difficulty parameter
Controller:
def index
if params[:difficulty]
#questions = Question.all.where(:difficulty => params[:difficulty])
else
#questions = Question.all
end
end
routes.rb
resources :questions
You should provide a little more information, but maybe this will point you in the right direction if you are running a rails framework. I would create associations within the database objects so they can share certain characteristics. Check this out and see if this is what you're trying to do, http://guides.rubyonrails.org/association_basics.html . As for as the controller, that is where you'll define the method for calling the associations.

kaminari - redirect to last page

So I've got pagination with Kaminiari set up on my app, which is a forum. When someone replies to the thread, I want to direct them to the last page of the thread. It seems like it'd be easy enough to hard code the logic to get the last page based on what I'm using for record numbers, but is there a built in method to get the last page?
In my current version of kaminari (v0.12.4) the following works:
users = User.page(params[:page])
last_page = users.num_pages
num_pages is defined in https://github.com/amatsuda/kaminari/blob/master/lib/kaminari/models/page_scope_methods.rb.
If you want to add a last_page method, I suggest the following:
module Kaminari
module PageScopeMethods
def last_page
num_pages
end
end
end
It seems that this thread has an answer.
You can write a method to achieve this if not already present in Kaminari . This should be present since Kaminari also renders the page numbers for navigation.
Say, #records is list of db records where you performed #records.page(1) to show the get the current set of records,
The last page number is defined by (#records.total_count / per_page.to_f).ceil .
For other people's sake, I'll share what worked for me.
Associations
Conversation has_many Messages
Message belongs_to Conversation
In Conversation show page, I want to paginate every 10 messages
messages = conversation.messages.page(params[:page]).per(10)
last_page = messages.total_pages
Then I want to create a link to this show page which will show me the last page. I just made a helper method
def create_link_to_last_page(conversation)
content_tag :div do
link_to("Show", url_for(controller: 'conversations', action: 'show', id: conversation.id, page: last_page))
end
end

Rails 3 rateable model - How to create ajax rating?

How do I create some simple ajax rating like there is on this page http://watir.com/documentation/ ? Every visitor should be able to rate, I dont need to set permissions. I want to store the ratings in a column. So the user can sort by ratings.
Please make an detailled example. I am not a javascript expert.
I have found an example to create ratings from scratch. But it authorizes a user.
Can someone show me a guidance to create ratings without a Rater (user)? It should not only store the values but also count the votes.
http://eighty-b.tumblr.com/post/1569674815/creating-an-ajaxified-star-rating-system-in-rails-3
What I did recently to add a simple rating mechanism to an existing project was the following:
I added two fields to an existing table (which contained the items to be rated). Those were:
rating_score => The current score
ratings => The number of ratings which led to the score
For example, if five users would've voted "5" for the current item, rating_score would be 25, and ratings would be 5. The current rating would be computed as rating_score / ratings.
Then I added a new method to the controller of the items to be rated, called "rate", which looked something like:
def rate
#item = Item.find(params[:id])
#container = "item"+#item.id.to_s
#item.rating_score += params[:rating].to_i
#item.ratings += 1
#item.save
respond_to do |format|
format.js
end
end
My view for that method, called rate.js.erb, would look something like
$('#<%= #container %>').html('<%= escape_javascript(render(partial: 'rating', locals: { item: #item })) %>');
This code works only if you've got jQuery installed, but it should be easily translatable to Prototype or whatever JS framework you may be using.
And the partial for the rating, called _rating.html.erb, was something like:
<%= form_tag url_for(controller: 'items', action: 'rate', id: item.id), remote: true %>
<%= rating_stars(item.rating_score, item.ratings) %>
<%= item.ratings %> Votes
</form>
In this partial, the rating_stars() helper method generated some kind of star-like representation for the rating, but you can do that however you like.
By setting "remote: true" in the form_tag helper, your Rails installation should automatically transmit the request via the installed Javascript framework. This magic is part of the whole unobtrusive javascript thing going on in Rails lately, which is actually pretty cool.
Hope this gives you an idea of how to realize a very simple rating system with no IP lock feature whatsoever in Rails.
Looks like the Watir documentation rating system is set up through polldaddy.
For this particular case, it appears they include the polldaddy javascript which populates the rating div container with their star rating widget. Looks like there's a corresponding javascript object which you can inspect:
console.log( PDRTJS_101132_page_2.avg_rating ); //=> 4
If you had numerous rating widgets like these on a page, and you were able to make a collection of the javascript objects paired with their divs, presumably you could sort them based on that average rating property.

Resources