how to show aggregation results on Rails 4 - ruby

Syntax in mongodb:
db.orders.aggregate(
{$unwind: "$lines"},
{$group :
{_id: {sku: "$lines.sku", desc: "$lines.description"},
qty : {$sum : 1}}},{ $sort : { qty : -1}}
)
I want to to show the result of the above query on Rails.
I'm using Mongoid with Rails 4 and my Gemfile:
gem 'mongoid', github: 'mongoid/mongoid'
As I understand, the only way to write the query above is to install gem for moped driver.
So, my 1st question is how that line should be declared in the Gemfile for Rails 4 and Ruby 2.0 ?
I assume the query in moped would look like:
Order.collection.aggregate(
{"$unwind" => "$lines"},
{"$group" => {"_id" => {"sku" => "$lines.sku", desc => "$lines.description"},
qty => {"$sum" => 1}}},
{ "$sort" => { "qty" => -1}})
I would like to show results of this query, by clicking a button on the index page without passing parameters.
The 2nd question is that I can't figure out how to change controller and index view page to put a button that will call this query.
UPDATE
index method part of the controller as below:
def index
#orders = if params[:search]
Order.search(params[:search]).queryable.asc(:_id).paginate(:page => params[:page], :per_page => 20)
elsif params[:search_from] && params[:search_to]
Order.search_date(params[:search_from], params[:search_to]).queryable.asc(:_id).paginate(:page => params[:page], :per_page => 20)
else
Order.shipping_today(Date.today, Date.today).queryable.asc(:_id).paginate(:page => params[:page], :per_page => 20)
end
index.html.erb:
<h1>Date: <%= Date.today %></h1>
<%= form_tag orders_path, :method => 'get' do %>
<p>Order date range:<br>
<%= text_field_tag :search_from, params[:search_from] %> - <%= text_field_tag :search_to, params[:search_to] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<%= form_tag orders_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<%= link_to "Reset", orders_path %>
</p>
<% end %>
<%= form_tag orders_path, :method => 'get' do %>
<p>
<%= submit_tag "Statistics", :name => nil %>
</p>
<% end %>
<div class="digg_pagination">
<div class="page_info">
<%= page_entries_info #orders %>
</div>
<%= will_paginate #orders, :container => false %>
</div>
<br />
<table border = 1 >
<thead>
<tr>
<th>Shipping date</th>
<th>Order #</th>
<th>Ship to name</th>
<th>Tracking #</th>
<th>Shipped</th>
<th>Action</th>
<th></th>
</tr>
</thead>
<tbody>
<% #orders.each do |order| %>
<tr>
<td><%= order.shipping_date %></td>
<td><%= link_to order.order_number, order_path(order) %></td>
<td><%= order.ship_to_fname %></td>
<td><%= order.track_num %></td>
<td><%= order.ship_date %></td>
<td><%= link_to 'Edit', edit_order_path(order) %></td>
<td><%= link_to 'New', new_order_path(order) %></td>
<td><%= link_to 'Destroy', order, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br />
<%= link_to 'New Order', new_order_path %>

The line in Gemfile that you wrote gem 'mongoid', github: 'mongoid/mongoid' should be enough for that query to work.
After aggregate commant you'll get an array with the result of the aggregation.
You can assign it to the instance variable in the controller and iterate on it in view.
For example:
# LinesController
def index
#lines = Order.collection.aggregate(
{"$unwind" => "$lines"},
{"$group" => {"_id" => {"sku" => "$lines.sku", desc => "$lines.description"},
qty => {"$sum" => 1}}},
{ "$sort" => { "qty" => -1}})
end
# lines/index.html.erb
<ul>
<% #lines.each do |line| %>
<li>
<b><%= line['_id']['sku'] %></b>
<%= line['qty'] %>
</li>
<% end %>
</ul>

Related

NoMethodError in Sections#edit similar issue to other

I am a bit new to Ruby and am writing a program from scratch... I'm getting an error and I can't figure out where it is coming from. I've spent over an hour and i'm sure it's something stupidly simple. I have other similar pages that work fine, but there's some issue with the instance variable. It's almost an identical problem as the link provided.
Here's my error:
Showing C:/Users/kevin/Desktop/ruby_test/sites/simple_cms/app/views/sections/_form.html.erb where line #4 raised:
undefined method `collect' for nil:NilClass
Extracted source (around line #4):
1 <table summary="Section form fields">
2 <tr>
3 <th><%= f.label(:page_id, "Page") %></th>
4 <td><%= f.select(:page_id, #pages.collect {|p| [p.name, p.id]}) %>
5 </td>
6 </tr>
7 <tr>
Trace of template inclusion: app/views/sections/edit.html.erb
Rails.root: C:/Users/kevin/Desktop/ruby_test/sites/simple_cms
Here's my forms page:
<table summary="Section form fields">
<tr>
<th><%= f.label(:page_id, "Page") %></th>
<td><%= f.select(:page_id, #pages.collect {|p| [p.name, p.id]}) %>
</td>
</tr>
<tr>
<th><%= f.label(:name) %></th>
<td><%= f.text_field(:name) %></td>
</tr>
<tr>
<th><%= f.label(:position) %></th>
<td><%= f.select(:position, 1..#section_count) %></td>
</tr>
<tr>
<th><%= f.label(:visible) %></th>
<td><%= f.check_box(:visible) %></td>
</tr>
<tr>
<th><%= f.label(:content_type) %></th>
<td>
<%= f.radio_button(:content_type, 'text') %> Text
<%= f.radio_button(:content_type, 'HTML') %> HTML
</td>
</tr>
<tr>
<th><%= f.label(:content) %></th>
<td><%= f.text_area(:content, :size => '40x10') %></td>
</tr>
</table>
Here's my controller:
class SectionsController < ApplicationController
layout "admin"
def index
#sections = Section.sorted
end
def show
#section = Section.find(params[:id])
end
def new
#section = Section.new({:name => "Default"})
#pages = Page.order('position ASC')
#section_count = Section.count + 1
end
def create
#section = Section.new(section_params)
if #section.save
flash[:notice] = "Section created successfully."
redirect_to(:action => 'index')
else
#pages = Page.order('position ASC')
#section_count = Section.count
render('new')
end
end
def edit
#section = Section.find(params[:id])
end
def update
#section = Section.find(params[:id])
if #section.update_attributes(section_params)
flash[:notice] = "Section updated successfully."
redirect_to(:action => 'show', :id => #section.id)
else
#pages = Page.order('position ASC')
#section_count = Section.count
render('edit')
end
end
def delete
#section = Section.find(params[:id])
end
def destroy
section = Section.find(params[:id]).destroy
flash[:notice] = "Section destroyed successfully."
redirect_to(:action => 'index')
end
private
def section_params
params.require(:section).permit(:page_id, :name, :position, :visible, :content_type, :content)
end
end
Here's the view page (edit):
<% #page_title = "Edit Section" %>
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div class="sections edit">
<h2>Update Section</h2>
<%= form_for(:section, :url => {:action => 'update', :id => #section.id}) do |f| %>
<%= render(:partial => "form", :locals => {:f => f}) %>
<div class="form-buttons">
<%= submit_tag("Update Section") %>
</div>
<% end %>
</div>
You should define #pages and #section_count variables in appropriate controller action:
def edit
#section = Section.find(params[:id])
#pages = Page.order('position ASC')
#section_count = Section.count
end
You also have a mistake in create action. When it doesn't create a record, #section_count should be Section.count + 1 as in new action.
Your controller could be also refractor to this

rails 3 ActiveRecord::StatementInvalid

I am making a search to my index.html.erb and it gives me an error.
This is my index.html.erb:
<% provide(:title, 'All configurations') %>
<h1>All configurations</h1>
<%= form_tag conf_show_all_path, :method => 'get' do %>
<%= hidden_field_tag :direction, params[:direction] %>
<%= hidden_field_tag :sort, params[:sort] %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<table class="pretty" border="1" cellpadding="10">
<tr>
<th><%= sortable("machine_name", "M.Name") %></th>
<th><%= sortable("machine_brand", "M.Brand") %></th>
<th><%= sortable("machine_model", "M.Model") %></th>
<th><%= sortable("control_unit_brand", "C.Unit Brand") %></th>
<th><%= sortable("control_unit_model", "C.Unit Model") %></th>
<th><%= sortable("tool_axis_x", "Axis X") %></th>
<th><%= sortable("tool_axis_y", "Axis Y") %></th>
<th><%= sortable("tool_axis_z", "Axis Z") %></th>
<th><%= sortable("rotary_axis_number", "R.Axis") %></th>
<th><%= sortable("linear_axis_number", "L.Axis") %></th>
<th><%= sortable "description" %></th>
<th><%= sortable("name", "Developer") %></th>
<th><%= sortable "updated_at" %></th>
</tr>
<% for conf in #confs %>
<tr class="<%= cycle('oddrow', 'evenrow') -%>">
<td><%= link_to conf.machine_name, conf %></td>
<td><%= conf.machine_brand %></td>
<td><%= conf.machine_model %></td>
<td><%= conf.control_unit_brand %></td>
<td><%= conf.control_unit_model %></td>
<td><%= conf.tool_axis_x %></td>
<td><%= conf.tool_axis_y %></td>
<td><%= conf.tool_axis_z %></td>
<td><%= conf.rotary_axis_number %></td>
<td><%= conf.linear_axis_number %></td>
<td><%= conf.description %></td>
<td><%= conf.developer.name unless conf.developer_id.blank? %></td>
<td><%= conf.updated_at %></td>
</tr>
<% end %>
</table>
<%= will_paginate #confs %>
This is search in conf.rb:
def self.search(search)
if search
q = "%#{search}%"
where('machine_name LIKE ? OR
machine_brand LIKE ? OR
machine_model LIKE ? OR
control_unit_brand LIKE ? OR
control_unit_model LIKE ? OR
tool_axis_x LIKE ? OR
tool_axis_y LIKE ? OR
tool_axis_z LIKE ? OR
rotary_axis_number LIKE ? OR
linear_axis_number LIKE ? OR
description LIKE ? OR
developer_id LIKE ? OR
updated_at LIKE ? OR',
q,q,q,q,q,q,q,q,q,q,q,q,q)
else
scoped
end
end
This is sortable method in application_helper.rb:
def sortable(column, title = nil)
title ||= column.titleize
css_class = (column == sort_column) ? "current #{sort_direction}" : nil
direction = (column == sort_column && sort_direction == "asc") ? "desc" : "asc"
link_to title, params.merge(:sort => column, :direction => direction, :page => nil), {:class => css_class}
end
Finally, this is the error:
ActiveRecord::StatementInvalid in Confs#index
SQLite3::SQLException: no such column: name: SELECT "confs".* FROM "confs" ORDER BY name asc LIMIT 10 OFFSET 0
Extracted source (around line #30)
Line 30 is this:
What is the problem and how can I fix it?
ok, search in conf.rb should updated_at LIKE ?' instead of updated_at LIKE ? OR' this was one syntax error. About question, I changed sort_column in confs_controller.rb from ...params[:sort] : "name" to ...params[:sort] : "machine_name"

rails 3 table complicated sorting

I am making a sorting function in order to sort a list of users. This sorting function designed to sort according to attributes (columns). User model has a column company_id but I don't want to sort by number, I want to sort by name of the company. BTW,
company :has_many users
and
user :belongs_to company
This is my index.html.erb:
<table class="pretty" border="1" cellpadding="10">
<tr>
<th></th>
<th><%= sortable "name" %></th>
<th><%= sortable "email" %></th>
<th><%= sortable "company_id" %></th>
<th>DELETE</th>
</tr>
<% for user in #users %>
<tr class="<%= cycle('oddrow', 'evenrow') -%>">
<td><%= gravatar_for user %></td>
<td><%= link_to user.name, user %></td>
<td><%= user.email %></td>
<td><%= user.company.name unless user.company_id.blank? %></td>
<td><% if current_user.admin? || ( ( current_user.developer? && !current_user?(user) ) && (user.boss_id == current_user.id) ) %>
|| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %></td>
</tr>
<% end %>
</table>
<%= will_paginate #users %>
This is sortable function from application_helper.rb:
def sortable(column, title = nil)
title ||= column.titleize
css_class = (column == sort_column) ? "current #{sort_direction}" : nil
direction = (column == sort_column && sort_direction == "asc") ? "desc" : "asc"
link_to title, params.merge(:sort => column, :direction => direction, :page => nil), {:class => css_class}
end
And this is users_controller.rb:
helper_method :sort_column, :sort_direction
def index
#users = User.where(:developer => false, :admin => false).search(params[:search]).order(sort_column + ' ' + sort_direction).paginate(:per_page => 10, :page => params[:page])
end
private
def sort_column
User.column_names.include?(params[:sort]) ? params[:sort] : "name"
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
end
So, how can I modify this in order to sort by Company.name rather than User.company_id?
I solved this by changing <%= sortable "company_id" %> to <%= sortable("name", "Company") %> and changing
User.column_names.include?(params[:sort]) ? params[:sort] : "name"
to
(( User.column_names.include?(params[:sort]) ) || ( Company.column_names.include?(params[:sort]) )) ? params[:sort] : "name"

Selecting a specific metafield for a product using Shopify API, Ruby on Rails

In liquid templates this is achieved like so:
{{ product.metafields.book.author }}
Which returns the value of 'author' for it's key 'book'
I'm using Shopify API and Ruby on Rails and have successfully looped over each metafield for a given product:
In the controller:
#products = ShopifyAPI::Product.find(:all, :params => {:limit => 10})
In the view:
<% #products.metafields.each do |metafield| %>
<%= metafield.key %> : <%= metafield.value %>
<% end %>
This returns all of the metafields for a product, as expected. How do I return only those metafields matching a specific key i.e. 'book' from the example above?
# add metafield
product = ShopifyAPI::Product.find(product_id)
product.add_metafield(ShopifyAPI::Metafield.new({
:description => 'Author of book',
:namespace => 'book',
:key => 'author',
:value => 'Kurt Vonnegut',
:value_type => 'string'
}))
# retrieve metafield
author = ShopifyAPI::Metafield.find(:first,:params=>{:resource => "products", :resource_id => product.id, :namespace => "book", :key => "author"}).value
More info: http://www.shopify.com/technology/3032322-new-feature-metafields
This seems to do the trick:
<% product.metafields.each do |metafield| %>
<% if metafield.key == "book" %>
<%= metafield.key %>: <%= metafield.value %><br/>
<% end %>
<% end %>
or
<% product.metafields.each do |metafield| %>
<% if metafield.key.include?("book") %>
<%= metafield.key %>: <%= metafield.value %><br/>
<% else %>
<% end %>
This works:
ShopifyAPI::Metafield.find(:first,:params=>{:resource => "products", :resource_id => 94549954, :key => "book"})
ShopifyAPI::Metafield.find(:all,:params=>{:product_id => product.id, :key=> 'book'})
You can get all metafields for a product
#product = ShopifyAPI::Product.find(params[:id])
After that, you can get its metafields
#metafields = #product.metafields
Or if you need just a specific metafield for that product
#metafield = ShopifyAPI::Product::Metafield.find(:all, where: {"product_id = ? AND metafield.key = ?", product.id, "book"})

Search, Sort with AJAX

I've reproduced the code from RailsCasts episode 240. I have no idea why with this code the Ajax requests don't work. The search function works with the normal method (reload page) sadly not through Ajax. The sort function works not at all.
I've included following JavaScript libraries:
application.js
jQuery JavaScript Library v1.6.2
jQuery UI 1.8.15
jQuery.rails.js
jQuery TinySort v1.1.0
If you need more information please let me know. I hope really you can help me to solve the problems.
users_controller.rb
def index
#users = User.search(params[:search]).order(sort_column + " " + sort_direction)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
end
def sort_column
User.column_names.include?(params[:sort]) ? params[:sort] : "lastname"
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
end
index.html.erb
<h1>Listing users</h1>
<%= form_tag users_path, :method => 'get', :id => "users_search" do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<div id="users">
<%= render 'users' %>
</div>
<% end %>
_users.html.erb
<%= hidden_field_tag :direction, params[:direction] %>
<%= hidden_field_tag :sort, params[:sort] %>
<table class="pretty">
<tr>
<th><%= sortable "Last name" %></th>
<th><%= sortable "First name" %></th>
</tr>
<% for user in #users %>
<tr>
<td><%= user.lastname %></td>
<td><%= user.firstname %></td>
</tr>
<% end %>
</table>
index.js.erb
$("#users").html("<%= escape_javascript(render("users")) %>");
users_helper.rb
def sortable(column, title = nil)
title ||= column.titleize
css_class = column == sort_column ? "current #{sort_direction}" : nil
direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc"
link_to title, params.merge(:sort => column, :direction => direction, :page => nil), {:class => css_class}
end
application.js
$(function() {
$("#users th a").live("click", function() {
$.getScript(this.href);
return false;
});
$("#users_search input").keyup(function() {
$.get($("#users_search").attr("action"), $("#users_search").serialize(), null, "script");
return false;
});
});
Thank you for your help!
For the above code to work, you have to delete the following lines of code.
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
Now it works. :-)

Resources