I'm using the Twilio API in a rails app to show a user a list of their recordings. Say a user has 11 recordings total, and I'm showing them 3 per page.
twilio_controller.rb
def calls
#user = current_user
#account_sid = #user.twilio_account_sid
#auth_token = #user.twilio_auth_token
#page_size = 3
#page = params[:page_id] || 0
#sub_account_client = Twilio::REST::Client.new(#account_sid, #auth_token)
#subaccount = #sub_account_client.account
#recordings = #subaccount.recordings
#recordingslist = #recordings.list({:page_size => #page_size, :page => #page})
end
calls.html.erb
<% #recordingslist.each do |recording| %>
<tr>
<td><%= recording.sid %></td>
</tr>
<% end %>
<%= link_to "Next Page", twilio_calls_path(#page + 1) %>
routes.rb
#twilio routes
post 'twilio/callhandler'
get 'twilio/calls'
match 'twilio/calls' => 'twilio#page', :as => :twilio_page # Allow `recordings/page` to return the first page of results
match 'twilio/calls/:page_id' => 'twilio#page', :as => :twilio_page
Paging info is built into the Twilio response such that
#recordingslist.next_page
gives me the next 3 recordings (verified in rails console). How do I link to that so that when a user clicks the link, the table loads the next 3 results?
Thanks!
You can use a gem like Kaminari for Pagination.
https://github.com/amatsuda/kaminari
I would recommend utilizing the paging functionality that ships with twilio-ruby. According to the docs:
ListResource.list() accepts paging arguments.
Start by create a route for your Twilio list view. Make sure you can pass a page_id parameter – this is how your controller action will know which page to render:
# config/routes.rb
match 'recordings/page/:page_id' => 'twilio#page', :as => :twilio_page
match 'recordings/page' => 'twilio#page', :as => :twilio_page # Allow `recordings/page` to return the first page of results
Then, in the page action, pull the page_id parameter (or set if to 1 if there is no page_id, and pass the page_number and page_size as arguments to #recordings.list:
# app/controllers/twilio_controller.rb
def page
page_size = 3
#page = params[:page_id] || 1
#sub_account_client = Twilio::REST::Client.new(#account_sid, #auth_token)
#subaccount = #sub_account_client.account
#recordings = #subaccount.recordings
#recordingslist = #recordings.list({:page_size => page_size, :page => page)})
end
Finally, in your view, pass the page number to twilio_page_path in your link_helper – just make sure to adjust the page number accordingly (+1 for the next page, -1 for the previous page:
# view
<%= link_to "Next Page", twilio_page_path(#page.to_i + 1) %>
<%= link_to "Previous Page", twilio_page_path(#page.to_i - 1) %>
Note that – if you're at the start or end of your list – you may inadvertently end up passing an invalid page_id. Therefore, you may want to implement some exception handling in your page controller action:
# app/controllers/twilio_controller.rb
def page
begin
#page = params[:page_id] || 1 # If `page_id` is valid
rescue Exception => e
#page = 1 # If `page_id` is invalid
end
# Remaining logic...
end
Related
I have built a 'NewsItem' controller that contains a method called 'top'. This is called by a javascript request to update a DIV on the page every 10 seconds. This is all working well.
def top(number = false)
# set the default value to use for the number
default_number = 10;
# perform checks on the variable
if number == false
if params.include?(:number)
number = params[:number]
else
number = default_number
end
end
# Run query to get the required news items
items = NewsItem.all( :order => ("created_at DESC"),
:include => [:profile],
:limit => number)
# iterate around the items that have been returned
#top_news = ""
items.each do |item|
#top_news += render_to_string :partial => "partials/news_item", :locals => {:item => item}
end
respond_to do |format|
format.html { render :partial => "partials/news_top"}
end
end
This is called with '/news/top' or '/news/top/20' to change the number of items that are returned.
The problem is that when the page is first loaded the 'news' DIV is empty for 10 seconds, until the JavaScript runs to update the DIV. So I want to ensure that the DIV is already populated by calling this function.
Now as I want the 'news' DIV to be available in all pages it is defined in the 'layouts/application.html.erb' template. So I need to call the 'top' method in the 'NewsItem' controller so that it can be rendered into the initial HTML. This is where I am struggling as I cannot work out how to use the 'helper_method' to make this available at this stage.
I have a feeling that I am missing something here and not understanding the whole process.
Thanks very much for any assistance.
Regards, Russell
Try separating out the logic. Maybe you make a method called top_news that returns the value you use in top_news. And since you're passing back a partial, use it to build the string. Partials are meant to be used to iterate over a list.
def index
#top_news = top_news
end
def top
#top_news = top_news
respond_to do |format|
format.html { render :partial => "partials/news_top"}
end
end
private
def top_news(number = false)
# set the default value to use for the number
default_number = 10;
# perform checks on the variable
if number == false
if params.include?(:number)
number = params[:number]
else
number = default_number
end
end
# Run query to get the required news items
items = NewsItem.all( :order => ("created_at DESC"),
:include => [:profile],
:limit => number)
# iterate around the items that have been returned
return render_to_string :partial => "partials/news_item", :collection => items, :as => :item
end
The other solution you can follow is to not render any partials in the controller at all except for your one javascript method and instead make a method in your model to do exactly what you're doing here.
class NewsItem
def top_news(number=20) # pass in number with default 20
NewsItem.where( :order => ("created_at DESC"),
:include => [:profile],
:limit => number)
end
end
Then just call it from your controllers to get that so you can use it in your views and iterate over it using partials in your views.
I'm new to Activeadmin and rails and I need some help.
I have a model that is paginated and I want to allow the user to change the pagination value or disable it completely, so it can print (to a printer) all the records (or filtered ones) for instance.
I know I can set the pagination using #per_page in :before_filter, but I can't figure out how I can change this value during execution.
To solve the problem of needing to show all the unpaginated records I defined a custom page, but in this page the filter or scope don't work so it's kind of useless.
How can I create a Print button in Active Admin?
This is a workaround to do it, I know it is not the best solution but it works ! :)
This is the app/admin/mymodel.rb file
ActiveAdmin.register MyModel do
before_filter :paginate
#other code
controller do
def paginate
#per_page = params[:pagination] unless params[:pagination].blank?
end
end
index do
panel "Pagination" do
render partial: "paginate", locals: {resource: "mymodels"}
end
#other code
end
#other code
end
And for the app/views/admin/articles/paginate.html.haml
#pagination_form
= form_tag do
= label_tag :pagination, "Number of " + resource + " per page : "
= text_field_tag :pagination
= submit_tag "Filter"
:javascript
$("#pagination_form form").submit(function(e){
e.preventDefault();
window.location = "/admin/#{resource}?pagination=" + $("#pagination").val();
})
Hoping that my answer can people with the same problem :)
I found a solution and I'm answering my own question for someone who has the same problem.
It may not be the best solution but it works, if someone has a better way please share:
ActiveAdmin.register mymodel do
before_filter :apply_pagination
# other code
index :download_links => false, :as => :table, :default => true do
if params[:pag].blank?
div link_to(I18n.t("text_for_the_link"), 'mymodel?pag=1', :class => "class_for_link")
else
div link_to(I18n.t("print.print"), 'mymodel', :class => "class_for_link")
end
# other code
end
controller do
def apply_pagination
if params[:pag].blank?
#per_page = 50
else
#per_page = 99999999
end
# other code
end
end
I found out you can define this by registering the following line on the resource:
ActiveAdmin.register MyModel do
config.per_page = [20, 50, 100, 200]
end
It automatically adds a select box in the index pagination with the preset values given in the array.
I'm performing AJAX search in my Rails application. Here is code from controller:
def show
#website = Website.find(params[:id])
if (current_user.id != #website.user_id)
redirect_to root_path
flash[:notice] = 'You are not owner!'
end
if params[:report] && params[:report][:start_date] && params[:report][:end_date]
#performance_reports = #website.performance_reports.where("created_at between ? and ?", params[:report][:start_date].to_date, params[:report][:end_date].to_date)
else
#performance_reports = #website.performance_reports
end
but when I'm trying to generate Excel document it alway goes to branch without params, because there are no params in URL.
One man reccomend me to use this post. I tried to implement it, but couldn't.
I don't understand this post enough, I just can't get where data is passing(spreadsheet gem)
Here is code:
def export
#website = Website.last
#data = #website.performance_reports
report = Spreadsheet::Workbook.new
spreadsheet = StringIO.new
contruct_body(spreadsheet, #data)
report.write spreadsheet
send_data spreadsheet.string, :filename => "yourfile.xls", :type => "application/vnd.ms-excel"
end
and it gives me error:
undefined method `contruct_body'
Code from view:
<%= form_tag( url_for, :method => :get, :id => "report") do%>
...show action posted above...
<% end %>
<%= link_to export_path do%>
<b>Export</b>
<% end %>
...working code without AJAX...
<%= link_to url_for(request.parameters.merge({:format => :xls})) do%>
<b>Export</b>
<% end %>
Please tell me where is my mistake or suggest ano
For the first problem, you need to show the view code and the path ajax is taking. Give us more information how the excel is being called.
For the second issue, you need to define that method. Specify how you will populate the spreadsheet with the data. Here is the guide. https://github.com/zdavatz/spreadsheet/blob/master/GUIDE.txt
== Writing is easy
As before, make sure you have Spreadsheet required and the client_encoding
set. Then make a new Workbook:
book = Spreadsheet::Workbook.new
Add a Worksheet and you're good to go:
sheet1 = book.create_worksheet
This will create a Worksheet with the Name "Worksheet1". If you prefer another
name, you may do either of the following:
sheet2 = book.create_worksheet :name => 'My Second Worksheet'
sheet1.name = 'My First Worksheet'
Now, add data to the Worksheet, using either Worksheet#[]=,
Worksheet#update_row, or work directly on Row using any of the Array-Methods
that modify an Array in place:
sheet1.row(0).concat %w{Name Country Acknowlegement}
sheet1[1,0] = 'Japan'
row = sheet1.row(1)
row.push 'Creator of Ruby'
row.unshift 'Yukihiro Matsumoto'
sheet1.row(2).replace [ 'Daniel J. Berger', 'U.S.A.',
'Author of original code for Spreadsheet::Excel' ]
sheet1.row(3).push 'Charles Lowe', 'Author of the ruby-ole Library'
sheet1.row(3).insert 1, 'Unknown'
sheet1.update_row 4, 'Hannes Wyss', 'Switzerland', 'Author'
Add some Formatting for flavour:
sheet1.row(0).height = 18
format = Spreadsheet::Format.new :color => :blue,
:weight => :bold,
:size => 18
sheet1.row(0).default_format = format
bold = Spreadsheet::Format.new :weight => :bold
4.times do |x| sheet1.row(x + 1).set_format(0, bold) end
And finally, write the Excel File:
book.write '/path/to/output/excel-file.xls'
I have a typical search facility in my app which returns a list of results that can be paginated, sorted, viewed with a different records_per_page value, etc. Each of these options is controlled by parameters in the query string. A simplified example:
/search?q=test&page=2
Now say I need to display a set of links that set records_per_page value to 10, 20, 30. Each link must include the existing query parameters, which can be a very long set, plus a new per_page parameter.
/search?q=test&page=2& ... &per_page=10
/search?q=test&page=2& ... &per_page=20
/search?q=test&page=2& ... &per_page=30
Is there an easy way to do it with just link_to helper or I need to parse and reproduce the query string from previous request somehow?
link_to 'Link', request.query_parameters.merge({:per_page => 20})
link_to 'Link', params.merge({:per_page => 20})
The simplest way to merge the new params with the query parameters and NOT with all parameters (including those obtained through the path) is to merge with request.query_parameters
link_to 'Search', search_path(request.query_parameters.merge({ per_page: 20 }))
Otherwise you end up with query strings duplicating the path parameters, for example ?action=index&controller=products&foo=bar instead of ?foo=bar.
If you want to keep existing params and not expose yourself to XSS attacks, be sure to clean the params hash, leaving only the params that your app can be sending:
# inline
<%= link_to 'Link', params.slice(:sort).merge(per_page: 20) %>
If you use it in multiple places, clean the params in the controller:
# your_controller.rb
#params = params.slice(:sort, :per_page)
# view
<%= link_to 'Link', #params.merge(per_page: 20) %>
You can just throw elements of the params hash at link_to. Like
link_to "some_other_link", "/search", :page => params[:page]
This works if the links you are processing aren't given to you by request.params.
require 'rack/utils'
require 'uri'
def modify_query url, options={}
uri = URI(url)
query_hash = Rack::Utils.parse_query(uri.query)
query_hash.merge!(options)
uri.query = Rack::Utils.build_query(query_hash)
uri.to_s
end
puts modify_query('/search?q=test&page=2&per_page=10', 'per_page' => 20)
puts modify_query('/search?q=test&page=2', 'per_page' => 30)
# Outputs
# /search?q=test&page=2&per_page=20
# /search?q=test&page=2&per_page=30
What about
<%= link_to 'Whatever', :overwrite_params => { :pear_page => 20 } %>
?
A bit late i know..
If your using this as a way to filter search results have a look at my helper :)
This automagicly removes all blank and unneeded params and add the class "selected" if all of it's new params were already set.
def search_to s, args={}
selected = 0
args.each do |k, v|
selected = selected + 1 if params[k] == v.to_s || ( params[k].nil? && v.blank? )
end
if #search_params_base.nil?
#search_params_base = request.parameters.clone
#search_params_base.delete(:action)
#search_params_base.delete(:controller)
#search_params_base.delete(:page)
#search_params_base.delete_if{|k, v| v.nil? || v.blank?}
#search_params_base.delete(:utf8) if #search_params_base[:keywords].nil?
end
search_params = #search_params_base.merge(args)
search_params.delete_if{|k, v| v.nil? || v.blank?}
link_to s, search_path + '?' + search_params.to_param, :class => selected == args.length ? 'selected' : nil
end
You can then just use this in your view:
search_to '$80 to $110', :price => 80..110
Or in your case:
search_to '30 per page', :page => params[:page], :per_page => 30
Is there a way to pass parameters with a link_to call without it showing up on the URL? I'm making a simple star-rating system, and I'm basically making each star an image link that passes its value as a parameter to a new rendering of the same page. The helper code looks like this:
def stars_generator(edit_mode = false)
#rating = params[:stars].to_i #takes rating from page param, so :star must be defined first!
#stars = Array.new(5) {|i| i+1} #change array size for more stars
output = "<div class = 'star_container'>"
case edit_mode #checks whether to display static stars or clickable stars
when true
#stars.each do |star| #this block generates empty or colored stars depending the value of #rating and the position of the star evaluated
if star <= #rating
output += link_to image_tag('star_rated.png', :mouseover => 'star_hover.png'), review_new_url(:stars => star)
else
output += link_to image_tag('star_empty.png', :mouseover => 'star_hover.png'), review_new_url(:stars => star)
end
end
when false #static stars are displayed if edit_mode is false
#stars.each do |star|
if star <= #rating
output += image_tag('star_rated.png')
else
output += image_tag('star_empty.png')
end
end
end
output += "</div>"
return output
end
It works perfectly, but currently the star rating shows up as a param in the URL. I would ideally want to hide that information somehow, and I've tried both hidden_field_tag and hidden_tag, neither of which work. Is there no way to do this or am i just completely noob?
you can try
link_to image_tag('star_rated.png', :mouseover => 'star_hover.png'), review_new_url(:stars => star), :method => :post
this will dynamically inject javascripts to turn the links into a form and submit the parameters through posting
hope that helps =)