How to use math in controller variables - ruby-on-rails

I simply need to be able to use math to set the end point of a query in my controller.
class WelcomeController < ApplicationController
def index
#video = Video.last
#videos = Video.last(7).reverse!.drop(1)
end
def show
#video = Video.find(params[:id])
#videos = Video.where(:id => start..stop)
end
end
This line: #videos = Video.where(:id => start..stop) should be something like #videos = Video.where(:id => params[:id]..params[:id]-7) because that array is supposed to be the next seven database entries after #video.
I'm also certain there's a better way to accomplish what I'm trying to do but I have no idea what it is.

One way to solve this is using a gem called will_paginate, which will automatically do what you are trying to solve
Example would be
#videos = Video.paginate(page: params[:page] || 1, per_page: 5)
you can get the page from the params, so your web page has to request something like this /videos?page=2
Other gem in this category is Kaminari

Related

Why is my instance variable being overwritten inside my Rails controller action?

I have two variables in my index action in my post controller. However I am using the kaminari gem and it requires that the variable for how many post per pages go in the index action.
However, I have another variable for my search. I don't want to over ride so what is a work around?
def index
#posts = Post.where(["title LIKE ?", "%#{params[:search]}%"])
#posts = Post.page(params[:page]).per(10)
end
Have you tried
#posts = Post.where(["title LIKE ?", "%#{params[:search]}%"]).page(params[:page]).per(10)
or this
#posts = Post.where(["title LIKE ?", "%#{params[:search]}%"])
#posts = #posts.page(params[:page]).per(10)
The way you have it set now the second #posts variable will override the first #posts variable every time 100% because you are just simply reassigning it.

How do I create a variable in the controller for single or multiple params

def index
#users = User.all.paginate(page: params[:page])
#users = User.named(params[:name]).paginate(page: params[:page]) if params[:name].present?
#users = User.countryname(params[:country]).paginate(page: params[:page]) if params[:country].present?
#users = User.gender(params[:gender_type]).paginate(page: params[:page]) if params[:gender_type].present?
end
The following code works fine if only :name or :country or :gender_type is present. But it does not work if multiple params are present. What is the DRY way of writing this code for multiple params? Obviously, I do not want to create a different line of code for each possible combination of params.
Here are the scopes:
class User
scope :countryname, -> (country) { where("country ILIKE ?", "%#{country}%")}
scope :gender, -> (gender_type) { where gender_type: gender_type}
scope :named, -> (name) { where("name ILIKE ?", "%#{name}%")}
If I have a query string of
example.com/users?name=sam&gender_type=male
it simply returns all users with names like sam and ignores their gender... I would need to code:
#users = User.gender(params[:gender_type]).named(params[:name]).paginate(page: params[:page]) if params[:gender_type] && params[:name].present?
but I do not want to have to write a new line of code for every single combination of parameters.
You could use the ruby try method. For example, you could write something like
#users = User.try(:gender, params[:gender_type]).try(:paginate, page: params[:page])
Look at try in api docs for other ways to use it.
the problem was the code should be
#users = User.all.paginate(page: params[:page])
#users = #users.named(params[:name]).paginate(page: params[:page]) if params[:name].present?
etc
Rails will then allow chain scoping automatically. the previous code creates separate independent non-chained instance variables.

Refactoring a similar controller's action

I used Pull Review for reviewing my app's code and it came back with this:
Consider refactoring, similar code detected.
Occurred at:
SkillsController # index
PagesController # index
So the app/controllers/skills_controller.rb index action code is:
def index
#skill = Skill.new
if params[:search]
#skills = Skill.search(params[:search]).order('created_at DESC')
else
#skills = Skill.all.order('created_at DESC')
end
end
and on app/controllers/pages_controller.rb is:
def index
#users = User.all
if params[:search]
#users = User.search(params[:search]).order('created_at DESC')
else
#users = User.all.order('created_at DESC')
end
end
Am I suppose to somehow refactor these two actions on these two controllers? Also, I am not sure how I refactor this. Do I extract the if params[:search] segment and replace the instance variables with another variable that will be used on both actions?
Thanks for your time.
I don't know where your method search comes from. It seems it comes from a custom module/gem for ActiveRecord.
If so, you can change the method to shorten code in controller
def self.search(args)
return self unless args
original_search_logic args
end
# As well as extract order to a scope
scope :by_time, -> { order('created_at DESC') }
Then in controller:
# Skill
def index
#skills = Skill.search(params[:search]).by_time
end
# User
def index
#users = User.search(params[:search]).by_time
end
These should be dry enough for now.
take a look at the has_scope and inherited_resources. You can extract the params[:search] part with has_scope. And use inherited_resources to extract how to get the collection and do the ordering.

Rails 4 json return on API

I'm creating an API on my application. I currently overrided the as_json method in my model in order to be able to get attached files as well as logo from Paperclip :
def as_json( options = {} )
super.merge(logo_small: self.logo.url(:small), logo_large: self.logo.url(:large), taxe: self.taxe, attachments: self.attachments)
end
Then within my controller, I'm doing :
def index
#products = current_user.products
respond_with #products
end
def show
respond_with #product
end
The problem is that on the index, I don't want get all the attachments. I only need it on the show method. So I tried it :
def index
#products = current_user.products
respond_with #products, except: [:attachments]
end
But unfortunately it's only working on default product attributes (everyting that I merged seems not to be consider). How can I do to not send :attachments?
Thanks
I'd recommend you have a look at active_model_serializers. It will provide a nice and OOP way of handling the kind of object decoration you need - selectively excluding attributes - and much more. There's even a Railscast!

Activeadmin: disable pagination when exporting xml/json

How can I disable pagination for json/xml export in activeadmin? I could't figure out any solution for this. I'm getting only current page when hitting export to xml or json.
One solution (no the best) is disable de pagination with a before_filter
controller do
before_filter :disable_pagination, :only => [:index]
def disable_pagination
#per_page = YourModel.count
end
end
This make a pagination with only one page for all the records, so it is going to export all the records.
This can also be done like this,
controller do
def index
super do |format|
per_page = (request.format == 'text/html') ? 30 : 10_000 # to skip the pagination
params[:page] = nil unless (request.format == 'text/html') #It will be working even after we export the CSV on the paginated sections.
#users = #users.order("first_name asc, last_name asc").page(params[:page]).per(per_page)
#users ||= end_of_association_chain.paginate if #users.present?
end
end
end

Resources