JSONApi part1

This commit is contained in:
2015-09-02 15:52:48 +02:00
parent 5d1ecd81c8
commit f47a8a9ed0
51 changed files with 386 additions and 141 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ gem 'slim-rails'
# Gems used only for assets and not required # Gems used only for assets and not required
# in production environments by default. # in production environments by default.
gem 'active_model_serializers', '~> 0.9.3' # explicitly outside assets gem 'active_model_serializers', '~> 0.10.0.rc2' # explicitly outside assets
group :assets do group :assets do
gem 'jquery-rails' gem 'jquery-rails'
gem 'jquery-ui-rails' gem 'jquery-ui-rails'
+4 -4
View File
@@ -67,8 +67,8 @@ GEM
activemodel (>= 3.0.2, < 5.0) activemodel (>= 3.0.2, < 5.0)
activesupport (>= 3.0.2, < 5.0) activesupport (>= 3.0.2, < 5.0)
active_decorator (0.5.3) active_decorator (0.5.3)
active_model_serializers (0.9.3) active_model_serializers (0.10.0.rc2)
activemodel (>= 3.2) activemodel (>= 4.0)
activejob (4.2.4) activejob (4.2.4)
activesupport (= 4.2.4) activesupport (= 4.2.4)
globalid (>= 0.3.0) globalid (>= 0.3.0)
@@ -236,7 +236,7 @@ GEM
http_parser.rb (0.6.0) http_parser.rb (0.6.0)
i18n (0.7.0) i18n (0.7.0)
iso_country_codes (0.7.1) iso_country_codes (0.7.1)
jquery-rails (4.0.4) jquery-rails (4.0.5)
rails-dom-testing (~> 1.0) rails-dom-testing (~> 1.0)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
@@ -465,7 +465,7 @@ DEPENDENCIES
ace-rails-ap ace-rails-ap
active_attr active_attr
active_decorator active_decorator
active_model_serializers (~> 0.9.3) active_model_serializers (~> 0.10.0.rc2)
airbrussh airbrussh
bourbon bourbon
cancancan cancancan
@@ -1,4 +1,4 @@
App.ListsIndexEntryComponent = Ember.Component.extend App.ListIndexEntryComponent = Ember.Component.extend
layoutName: 'lists/index-entry' layoutName: 'lists/index-entry'
classNames: ['lists-overview-entry'] classNames: ['lists-overview-entry']
classNameBindings: ['content.active:active'] classNameBindings: ['content.active:active']
@@ -4,7 +4,7 @@ App.MenuItemProductOrdersComponent = Ember.Component.extend
layoutName: 'components/menu/product_orders' layoutName: 'components/menu/product_orders'
classNames: ['menu-list-item', 'menu-list-item-product-orders'] classNames: ['menu-list-item', 'menu-list-item-product-orders']
classNameBindings: ['product_orders.length:show:hide', 'currentRoute:active'] classNameBindings: ['product_orders.length:show:hide', 'currentRoute:active']
currentRoute: (-> @get('targetObject.currentRouteName') is 'product_orders' ).property('targetObject.currentRouteName') currentRoute: Ember.computed.equal 'targetObject.currentPath', 'product-orders'
orderTotals: Ember.computed.mapBy 'product_orders', 'total' orderTotals: Ember.computed.mapBy 'product_orders', 'total'
orderTotal: Ember.computed.sum 'orderTotals' orderTotal: Ember.computed.sum 'orderTotals'
#orderTotal: Ember.computed 'product_orders.@each.total', -> #orderTotal: Ember.computed 'product_orders.@each.total', ->
@@ -2,9 +2,9 @@ App.MenuItemListNeedsHelpComponent = Ember.Component.extend Ember.ViewTargetActi
action: 'listNeedsHelp' action: 'listNeedsHelp'
layoutName: "components/menu/list_needs_help" layoutName: "components/menu/list_needs_help"
classNames: 'menu-list-item callout' classNames: 'menu-list-item callout'
classNameBindings: ['globals.list.needs_help:active'] classNameBindings: ['globals.active_list.needs_help:active']
click: -> click: ->
if @get('globals.list.needs_help') if @get('globals.active_list.needs_help')
@set 'globals.notice', t('list_needs_help.help_is_on_its_way') @set 'globals.notice', t('list_needs_help.help_is_on_its_way')
else else
@triggerAction() @triggerAction()
@@ -2,9 +2,9 @@ App.MenuItemListNeedsPaymentComponent = Ember.Component.extend Ember.ViewTargetA
action: 'listNeedsPayment' action: 'listNeedsPayment'
layoutName: "components/menu/list_needs_payment" layoutName: "components/menu/list_needs_payment"
classNames: 'menu-list-item callout' classNames: 'menu-list-item callout'
classNameBindings: ['controller.list.needs_payment:active'] classNameBindings: ['globals.active_list.needs_payment:active']
click: -> click: ->
if @get('controller.list.needs_payment') if @get('globals.active_list.needs_payment')
@set 'globals.notice', t('list_needs_payment.payment_already_requested') @set 'globals.notice', t('list_needs_payment.payment_already_requested')
else else
@triggerAction() #action: 'listNeedsPayment' @triggerAction() #action: 'listNeedsPayment'
@@ -14,14 +14,14 @@ App.NewProductOrdersListComponent = Ember.Component.extend
# @get('product_orders').invoke 'eraseRecord' # @get('product_orders').invoke 'eraseRecord'
orderProducts: -> orderProducts: ->
# table = @get('controllers.table.model') # table = @get('controllers.table.model')
# list = @get('globals.list') # list = @get('globals.active_list')
# order = @store.createRecord('order', list: list, table: table) # order = @store.createRecord('order', list: list, table: table)
# new_product_orders = @store.all('product_order').filterProperty('order', null) # new_product_orders = @store.all('product_order').filterProperty('order', null)
# order.get('product_orders').pushObjects(new_product_orders) # order.get('product_orders').pushObjects(new_product_orders)
# #
# order.save().then (response)=> # order.save().then (response)=>
# new_product_orders.invoke 'eraseRecord' # new_product_orders.invoke 'eraseRecord'
# if @get('globals.list') # if @get('globals.active_list')
# @transitionToRoute 'active_list' # @transitionToRoute 'active_list'
# else # else
# # Get list info from the server # # Get list info from the server
@@ -2,4 +2,4 @@ App.ActiveListController = Ember.Controller.extend
#orders: (-> #orders: (->
#@get('list.orders') #@get('list.orders')
#).property('list.orders') #).property('list.orders')
list: (-> @get('globals.list') ).property('globals.list') list: Ember.computed.alias 'globals.active_list'
@@ -1,5 +1,4 @@
App.ApplicationController = Ember.Controller.extend App.ApplicationController = Ember.Controller.extend
#list: Ember.computed.alias 'globals.list'
#notice: '' #notice: ''
actions: actions:
confirmCancel: -> confirmCancel: ->
@@ -10,7 +9,7 @@ App.ApplicationController = Ember.Controller.extend
@set 'globals.notice', '' @set 'globals.notice', ''
showSupplierStatusInfo: -> showSupplierStatusInfo: ->
@modal 'supplier_status_info', @modal 'supplier_status_info',
model: @get('globals.list.supplier') model: @get('globals.active_list.supplier')
title_path: 'supplier_status_info.title' title_path: 'supplier_status_info.title'
openDebugger: -> openDebugger: ->
@@ -21,14 +20,14 @@ App.ApplicationController = Ember.Controller.extend
).observes('currentPath') ).observes('currentPath')
events: events:
notify: (notification) -> @set 'globals.notice', notification.message notify: (notification) -> @set 'globals.notice', notification.message
list_helped: -> @set 'globals.list.needs_help', false list_helped: -> @set 'globals.active_list.needs_help', false
list_needs_help: -> @set 'globals.list.needs_help', true # incoming from other users list_needs_help: -> @set 'globals.active_list.needs_help', true # incoming from other users
list_is_paid: -> @set 'globals.list.needs_payment', false list_is_paid: -> @set 'globals.active_list.needs_payment', false
list_needs_payment: -> @set 'globals.list.needs_payment', true # incoming from other users list_needs_payment: -> @set 'globals.active_list.needs_payment', true # incoming from other users
list_closed: (data)-> list_closed: (data)->
@transitionToRoute('list', data.id).then => @transitionToRoute('list', data.id).then =>
@set 'globals.list.state', 'closed' @set 'globals.active_list.state', 'closed'
@set 'globals.list', null @set 'globals.active_list', null
order_being_processed: (data)-> order_being_processed: (data)->
order = @store.all('order').findBy 'id', data.id order = @store.all('order').findBy 'id', data.id
order.set('state', 'active') if order order.set('state', 'active') if order
@@ -65,7 +64,7 @@ App.ApplicationController = Ember.Controller.extend
join_request_approved: (data)-> join_request_approved: (data)->
return @transitionToRoute 'active_list' if @get('globals.list.id') # Not interested when there is an active list return @transitionToRoute 'active_list' if @get('globals.active_list.id') # Not interested when there is an active list
# The rest of the code is for the new user # The rest of the code is for the new user
@setCurrentList -> @setCurrentList ->
@transitionToRoute('active_list').then => @transitionToRoute('active_list').then =>
@@ -73,16 +72,16 @@ App.ApplicationController = Ember.Controller.extend
@set 'globals.join_request_sent', false @set 'globals.join_request_sent', false
list_changed_table: (data)-> list_changed_table: (data)->
@store.findRecord('table', data.to_table_id).then (table)=>@set('globals.list.table', table) @store.findRecord('table', data.to_table_id).then (table)=>@set('globals.active_list.table', table)
orders_in_process_count: (data)-> orders_in_process_count: (data)->
@set 'globals.list.supplier.orders_in_process_count', data.count @set 'globals.active_list.supplier.orders_in_process_count', data.count
orders_placed_count: (data)-> orders_placed_count: (data)->
@set 'globals.list.supplier.orders_placed_count', data.count @set 'globals.active_list.supplier.orders_placed_count', data.count
new_order: (data)-> new_order: (data)->
# return if @store.all('order').findProperty('id', data.order.id) # return if @store.all('order').findProperty('id', data.order.id)
@store.pushPayload data @store.pushPayload data
@store.findById('list', data.list.id).then (list)=> @set 'globals.list', list @store.peekRecord('list', data.list.id).then (list)=> @set 'globals.active_list', list
# @store.findById('order', data.order.id).then (order)-> # @store.peekRecord('order', data.order.id).then (order)->
# list = order.get('list') # list = order.get('list')
# list.get('orders').addObject(order) # list.get('orders').addObject(order)
@@ -92,15 +91,16 @@ App.ApplicationController = Ember.Controller.extend
list.set 'needs_payment', false list.set 'needs_payment', false
setCurrentList: (callback)-> setCurrentList: (callback)->
success = (list)=> success = (list)=>
#@store.find('list', 'current').deleteRecord() # gets not replaced, buty stays as dummy #@store.findRecord('list', 'current').deleteRecord() # gets not replaced, buty stays as dummy
# A list record with id current and with the content of the returned list is created # A list record with id current and with the content of the returned list is created
# at the moment remove the dummy list, this should be resolved by Ember eventually # at the moment remove the dummy list, this should be resolved by Ember eventually
if error_list = @store.peekRecord('list', 'current') # TODO: keek checking if peekAll can be replaced by peekRecord
if error_list = @store.peekAll('list', 'current').findBy('id', 'current') # peekRecord('list', 'current') not working in Ember 2.0.0
error_list.eraseRecord() error_list.eraseRecord()
#TODO: depricate list on application controller #TODO: depricate list on application controller
#@set 'list', list #@set 'list', list
@set 'globals.list', list @set 'globals.active_list', list
if list.get('join_requests.length') if list.get('join_requests.length')
@transitionToRoute 'join_requests' @transitionToRoute 'join_requests'
else if @currentRouteName is 'index' else if @currentRouteName is 'index'
@@ -112,7 +112,7 @@ App.ApplicationController = Ember.Controller.extend
#console.log "Error: #{emberError.message}" if emberError.message #console.log "Error: #{emberError.message}" if emberError.message
if error_list = @store.peekRecord('list', 'current') if error_list = @store.peekRecord('list', 'current')
error_list.eraseRecord() error_list.eraseRecord()
@set 'globals.list', null @set 'globals.active_list', null
switch @currentRouteName switch @currentRouteName
when 'table' then # nothing when 'table' then # nothing
else @redirect_to 'user_root' else @redirect_to 'user_root'
@@ -1,5 +1,5 @@
App.JoinRequestsController = Ember.Controller.extend App.JoinRequestsController = Ember.Controller.extend
join_requests: (-> @get('globals.list.join_requests') ).property('globals.list.join_requests') join_requests: Ember.computed.alias 'globals.active_list.join_requests'
actions: actions:
rejectRequest: (join_request)-> rejectRequest: (join_request)->
Ember.$.post("#{$data_host}/user/reject_join_request", user_id: join_request.get('user.id')).then (response)-> Ember.$.post("#{$data_host}/user/reject_join_request", user_id: join_request.get('user.id')).then (response)->
@@ -1,21 +1,19 @@
App.TableController = Ember.Controller.extend App.TableController = Ember.Controller.extend
tableCanTakeOrders: (-> tableCanTakeOrders: (->
return false unless @get('supplier.can_take_orders') return false unless @get('supplier.can_take_orders')
list = @get('globals.list') if list = @get('globals.active_list')
if list
return false unless list.get('supplier.id') == @get('supplier.id') return false unless list.get('supplier.id') == @get('supplier.id')
return false unless list.get('table.id') == @get('model.id') return false unless list.get('table.id') == @get('model.id')
true true
else else
# no list and open supplier # no list and open supplier
if @get('model.occupied') then false else true if @get('model.occupied') then false else true
).property('globals.list.id', 'supplier.can_take_orders', 'model.occupied', 'model.id', 'globals.list.table.id') ).property('globals.active_list.id', 'supplier.can_take_orders', 'model.occupied', 'model.id', 'globals.active_list.table.id')
supplier: Ember.computed 'model.supplier', -> @get('model.supplier') supplier: Ember.computed.alias 'model.supplier'
showJoinButton: (-> showJoinButton: Ember.computed 'globals.active_list.id', 'supplier.can_take_orders', 'model.occupied', 'model.id', 'globals.active_list.table.id', ->
return false unless @get('supplier.can_take_orders') return false unless @get('supplier.can_take_orders')
return false if @get('globals.list') # if you already have an active list, do not join another return false if @get('globals.active_list') # if you already have an active list, do not join another
if @get('model.occupied') then true else false # no point in joining tables that are not occupied if @get('model.occupied') then true else false # no point in joining tables that are not occupied
).property('globals.list.id', 'supplier.can_take_orders', 'model.occupied', 'model.id', 'globals.list.table.id')
actions: actions:
joinOccupiedTable: -> joinOccupiedTable: ->
Ember.$.post("#{$data_host}/user/join_occupied_table.json", table_id: @get('model.id')) Ember.$.post("#{$data_host}/user/join_occupied_table.json", table_id: @get('model.id'))
@@ -1,4 +1,4 @@
attr = DS.attr attr = DS.attr
App.JoinRequest= DS.Model.extend App.JoinRequest= DS.Model.extend
list: DS.belongsTo('list') list: DS.belongsTo('list', async: false)
user: DS.belongsTo('user') user: DS.belongsTo('user', async: false)
@@ -1,31 +1,31 @@
attr = DS.attr attr = DS.attr
App.List = DS.Model.extend App.List = DS.Model.extend
orders: DS.hasMany('order') needs_help: attr('boolean', defaultValue: false)
needs_help: attr('boolean') needs_payment: attr('boolean', defaultValue: false)
needs_payment: attr('boolean') user_requests_closing: attr('boolean', defaultValue: false)
user_requests_closing: attr('boolean')
state: attr('string') state: attr('string')
price: attr('number') price: attr('number')
closed_at: DS.attr('date') closed_at: attr('date')
extended_version: attr('boolean') extended_version: attr('boolean')
supplier_orders_in_process_count: attr('number') supplier_orders_in_process_count: attr('number')
supplier_orders_placed_count: attr('number') supplier_orders_placed_count: attr('number')
cached_supplier_name: attr('string')
supplier: DS.belongsTo('supplier') orders: DS.hasMany('order', async: true)
table: DS.belongsTo('table') supplier: DS.belongsTo('supplier', async: false)
join_requests: DS.hasMany('join_request') table: DS.belongsTo('table', async: true)
users: DS.hasMany('user') join_requests: DS.hasMany('join_request', async: false)
users: DS.hasMany('user', async: false)
is_extended_version: -> is_extended_version: ->
@get('extended_version') @get('extended_version')
relevant_orders: (-> @get('orders').filter((o)->o.get('state') isnt 'cancelled')).property('orders.@each.state') relevant_orders: Ember.computed 'orders.@each.state', -> @get('orders').rejectBy('state', 'cancelled')
sorted_orders: (-> @get('relevant_orders').sortBy('created_at').reverseObjects()).property('relevant_orders.@each.isLoaded') sorted_orders: (-> @get('relevant_orders').sortBy('created_at').reverseObjects()).property('relevant_orders.@each.isLoaded')
total: (-> total: (->
@get('relevant_orders').getEach('total').reduce(((sum, total) -> sum + total), 0) @get('relevant_orders').getEach('total').reduce(((sum, total) -> sum + total), 0)
).property('relevant_orders.@each.total') ).property('relevant_orders.@each.total')
active: (-> @get('state') is 'active' ).property('state') active: Ember.computed.equal 'state', 'active'
showTotal: (-> #showTotal: (->
if @get('orders.length') && @get('orders.length') > 1 then true else false # if @get('orders.length') && @get('orders.length') > 1 then true else false
).property('orders.length') #).property('orders.length')
showTotal: Ember.computed.gt 'relevant_orders.length', 1
@@ -1,9 +1,9 @@
attr = DS.attr attr = DS.attr
App.Order = DS.Model.extend App.Order = DS.Model.extend
state: attr 'string' state: attr 'string'
list: DS.belongsTo('list') list: DS.belongsTo('list', async: true)
table: DS.belongsTo('table') table: DS.belongsTo('table')
product_orders: DS.hasMany('product_order', embedded: 'always') product_orders: DS.hasMany('product_order', async: false)
total: (-> total: (->
@get('product_orders').getEach('total').reduce(((sum, total) -> sum + total), 0) @get('product_orders').getEach('total').reduce(((sum, total) -> sum + total), 0)
).property('product_orders.@each.quantity') ).property('product_orders.@each.quantity')
@@ -2,16 +2,16 @@ attr = DS.attr
App.ProductOrder = DS.Model.extend App.ProductOrder = DS.Model.extend
quantity: attr 'number', defaultValue: 1 quantity: attr 'number', defaultValue: 1
price: attr 'number' price: attr 'number'
product_name: attr('string') product_name: attr 'string'
product: DS.belongsTo('product')
product_variant: attr('string') product_variant: attr('string')
order: DS.belongsTo('order')
placed: attr('boolean', defaultValue: false) # virtual attribute for new orders to be placed, should be more elegant placed: attr('boolean', defaultValue: false) # virtual attribute for new orders to be placed, should be more elegant
product: DS.belongsTo('product', async: true)
order: DS.belongsTo('order', async: false)
increment: -> increment: ->
@set('quantity', @get('quantity') + 1) @set('quantity', @get('quantity') + 1)
total: (-> @get('quantity') * @get('price')).property('quantity', 'price') total: (-> @get('quantity') * @get('price')).property('quantity', 'price')
display: Ember.computed 'quantity', 'product_variant', 'product.name', -> display: Ember.computed 'quantity', 'product_variant', 'product_name', ->
disp = "#{@get('quantity')} x #{@get('product.name')}" disp = "#{@get('quantity')} x #{@get('product_name')}"
if variant = @get('product_variant') if variant = @get('product_variant')
disp = "#{disp} (#{variant})" disp = "#{disp} (#{variant})"
disp.htmlSafe() disp.htmlSafe()
@@ -7,8 +7,8 @@ App.Supplier= DS.Model.extend
orders_placed_count: attr('number') orders_placed_count: attr('number')
orders: DS.hasMany('order') orders: DS.hasMany('order')
product_categories: DS.hasMany('product_category') product_categories: DS.hasMany('product_category', async: true)
lists: DS.hasMany('list') lists: DS.hasMany('list', async: true)
is_extended_version: -> is_extended_version: ->
@get('extended_version') @get('extended_version')
@@ -4,4 +4,4 @@ App.Table= DS.Model.extend
needs_help: attr('boolean') needs_help: attr('boolean')
occupied: attr('boolean') occupied: attr('boolean')
supplier: DS.belongsTo('supplier') supplier: DS.belongsTo('supplier', async: true)
@@ -1,6 +1,6 @@
DS.Model.reopen DS.Model.reopen
created_at: DS.attr('date') #created_at: DS.attr('date')
updated_at: DS.attr('date') #updated_at: DS.attr('date')
eraseRecord: -> eraseRecord: ->
#@clearRelationships() #@clearRelationships()
@transitionTo('deleted.saved') @transitionTo('deleted.saved')
@@ -1,6 +1,6 @@
App.ActiveListRoute = Ember.Route.extend App.ResetScroll App.ActiveListRoute = Ember.Route.extend App.ResetScroll
#model: -> #model: ->
#@get('globals.list') #@get('globals.active_list')
#afterModel: -> #afterModel: ->
#controller = @controllerFor('application') #controller = @controllerFor('application')
#table_id = controller.get('list.table.id') #table_id = controller.get('list.table.id')
@@ -13,7 +13,7 @@ App.ApplicationRoute = Ember.Route.extend
unauthorized: -> unauthorized: ->
Qstorage.removeItem('auth_token') Qstorage.removeItem('auth_token')
Qstorage.removeItem('user_id') Qstorage.removeItem('user_id')
@set 'globals.list', null @set 'globals.active_list', null
#@send 'obtain_token' #@send 'obtain_token'
@controllerFor('application').redirect_to 'sign_in', message: 'unauthorized' @controllerFor('application').redirect_to 'sign_in', message: 'unauthorized'
@@ -76,13 +76,13 @@ App.ApplicationRoute = Ember.Route.extend
listNeedsPayment: -> listNeedsPayment: ->
@get('controller').secured -> @get('controller').secured ->
@set 'globals.list.needs_payment', true @set 'globals.active_list.needs_payment', true
Ember.$.post "#{$data_host}/user/list_needs_payment.json" Ember.$.post "#{$data_host}/user/list_needs_payment.json"
#Ember.$.post("#{$data_host}/user/list_needs_payment.json").then (res) => #Ember.$.post("#{$data_host}/user/list_needs_payment.json").then (res) =>
#@set('list.needs_payment', true) # also done by faye #@set('list.needs_payment', true) # also done by faye
listNeedsHelp: -> listNeedsHelp: ->
@get('controller').secured -> @get('controller').secured ->
@set 'globals.list.needs_help', true @set 'globals.active_list.needs_help', true
Ember.$.post "#{$data_host}/user/needs_help.json" Ember.$.post "#{$data_host}/user/needs_help.json"
#Ember.$.post("#{$data_host}/user/needs_help.json").then (res) => #Ember.$.post("#{$data_host}/user/needs_help.json").then (res) =>
#@set('list.needs_help', true) # also done by faye #@set('list.needs_help', true) # also done by faye
@@ -1,5 +1,5 @@
App.ListRoute = Ember.Route.extend App.ResetScroll, App.ListRoute = Ember.Route.extend App.ResetScroll,
model: (options)-> model: (options)->
@store.find 'list', options.list_id @store.findRecord 'list', options.list_id
afterModel: (model)-> afterModel: (model)->
model.reload() unless model.is_extended_version() model.reload() unless model.is_extended_version()
@@ -1,5 +1,5 @@
App.ListsRoute = Ember.Route.extend App.ResetScroll, App.ListsRoute = Ember.Route.extend App.ResetScroll,
model: -> model: ->
@store.find 'list' @store.findAll 'list'
setupController: (controller, model)-> setupController: (controller, model)->
controller.set('alreadyLoaded', true) controller.set('alreadyLoaded', true)
@@ -1,7 +1,10 @@
App.ApplicationSerializer = DS.ActiveModelSerializer.extend() #App.ApplicationSerializer = DS.ActiveModelSerializer.extend()
App.ApplicationAdapter = DS.ActiveModelAdapter.extend App.ApplicationSerializer = DS.JSONAPISerializer.extend
keyForAttribute: (attr, method)-> attr
#App.ApplicationAdapter = DS.ActiveModelAdapter.extend
App.ApplicationAdapter = DS.JSONAPIAdapter.extend
host: $data_host host: $data_host
namespace: 'user' namespace: 'user'
headers: #headers:
"Accept": "application/json, text/javascript; q=0.01" # "Accept": "application/json, text/javascript; q=0.01"
@@ -13,7 +13,7 @@ if list.closed_at
.display-row .display-row
.display-label=t 'models.supplier' .display-label=t 'models.supplier'
.display-field= list.supplier.name .display-field= list.supplier.name
if list.orders.isLoaded if list.isLoaded
if list.sorted_orders if list.sorted_orders
.list-orders-container .list-orders-container
each list.sorted_orders as |order| each list.sorted_orders as |order|
@@ -30,7 +30,7 @@ if list.orders.isLoaded
span=t 'active_list.no_orders_explanation' span=t 'active_list.no_orders_explanation'
br br
if list.table if list.table
link-to 'table' list.table class="button" = link-to 'table' list.table class="button"
span=t 'list_products.title' span=t 'list_products.title'
else else
span.loading.large span.loading.large
@@ -1,13 +1,13 @@
.row .row
h2=t 'active_list.title' h2=t 'active_list.title'
if list.orders.isLoaded if list.isLoaded
if list if list
partial "list_content" partial "list_content"
else else
p p
span=t 'active_list.not_active.message' span=t 'active_list.not_active.message'
br br
link-to 'index' class="button" = link-to 'index' class="button"
span= t 'active_list.not_active.home_button_text' span= t 'active_list.not_active.home_button_text'
else else
span.loading.large span.loading.large
@@ -9,9 +9,9 @@
a{action "scanQr" bubbles=false} a{action "scanQr" bubbles=false}
span.scan-qr-icon span.scan-qr-icon
span Scan QR span Scan QR
if globals.list.id if globals.active_list.id
li li
=link-to 'table' globals.list.table.id class="side-menu-list-products" =link-to 'table' globals.active_list.table.id class="side-menu-list-products"
span.fa.fa-cutlery span.fa.fa-cutlery
span.fa.fa-glass span.fa.fa-glass
= t 'list_products.title' = t 'list_products.title'
@@ -19,7 +19,7 @@
=link-to 'active_list' class="side-menu-active-list" =link-to 'active_list' class="side-menu-active-list"
span.active-list-icon span.active-list-icon
span= t 'active_list.title' span= t 'active_list.title'
if globals.list.join_requests.length if globals.active_list.join_requests.length
li li
=link-to 'join_requests' =link-to 'join_requests'
span= t 'models.plural.join_request' span= t 'models.plural.join_request'
@@ -2,11 +2,11 @@
.top-menu-bar .top-menu-bar
.menu-content .menu-content
section.main-buttons section.main-buttons
if globals.list.id if globals.active_list.id
link-to 'index' class="top-menu-logo with-list" link-to 'index' class="top-menu-logo with-list"
= image-tag 'user/logo-small.png' = image-tag 'user/logo-small.png'
= menu-item route="active_list" = menu-item route="active_list"
= menu-item route="table" route_param=globals.list.table.id = menu-item route="table" route_param=globals.active_list.table.id
= menu-item-list-needs-help = menu-item-list-needs-help
= menu-item-list-needs-payment = menu-item-list-needs-payment
else else
@@ -14,18 +14,18 @@
= image-tag 'user/logo-small.png' = image-tag 'user/logo-small.png'
= menu-item-scan-qr = menu-item-scan-qr
= menu-item-product-orders = menu-item-product-orders
if globals.list if globals.active_list
.extra-info{action "showSupplierStatusInfo"} .extra-info{action "showSupplierStatusInfo"}
.supplier-info-row .supplier-info-row
/ .supplier-name= list.supplier.name / .supplier-name= list.supplier.name
.table-number .table-number
|#&nbsp; |#&nbsp;
= globals.list.table.number = globals.active_list.table.number
.supplier-info-row .supplier-info-row
.counter.supplier-orders-placed-count .counter.supplier-orders-placed-count
= globals.list.supplier.orders_placed_count = globals.active_list.supplier.orders_placed_count
span.orders-placed-count-icon span.orders-placed-count-icon
.supplier-info-row .supplier-info-row
.counter.supplier-orders-in-process-count .counter.supplier-orders-in-process-count
= globals.list.supplier.orders_in_process_count = globals.active_list.supplier.orders_in_process_count
span.orders-in-process-count-icon span.orders-in-process-count-icon
@@ -1,3 +1,3 @@
span.created_at=time list.created_at span.created_at=time list.created_at
span.price.currency= currency list.price span.price.currency= currency list.price
span.name= list.cached_supplier_name span.name= list.supplier.name
@@ -24,6 +24,8 @@
.currency .currency
float: right float: right
margin-right: 0.5em margin-right: 0.5em
min-width: 60px
text-align: right
.list-order-container .list-order-container
background-position: left center background-position: left center
background-repeat: no-repeat background-repeat: no-repeat
@@ -0,0 +1,7 @@
module Users
module Lists
class OrdersController < Users::ApplicationController
respond_to :json
end
end
end
+8 -11
View File
@@ -7,24 +7,21 @@ module Users
#lists.include_relation(:supplier) #lists.include_relation(:supplier)
lists.reject!{|l| l.id == params[:exclude_list]} if params[:exclude_list].present? lists.reject!{|l| l.id == params[:exclude_list]} if params[:exclude_list].present?
lists.reject!{|l| l.id == current_user.active_list_id } if current_user && current_user.active_list_id.present? # see spec Loading lists and switching to the order products view works, lists loading may unlink active list orders lists.reject!{|l| l.id == current_user.active_list_id } if current_user && current_user.active_list_id.present? # see spec Loading lists and switching to the order products view works, lists loading may unlink active list orders
lists.include_relation(:users, :orders, :supplier) lists.include_relation(:users, :supplier)
render json: lists, each_serializer: UserListSerializer, meta: {total_pages: lists.total_pages, page: lists.current_page} #, root: :lists render json: lists, each_serializer: Users::ListSerializer, meta: {total_pages: lists.total_pages, page: lists.current_page} #, root: :lists
end end
#EMBER #EMBER
def current def current
list = current_user.active_list @list = current_user.active_list
render json: {}, status: :not_found and return unless list.present? show
[list].include_relation(supplier: {product_categories: :products}, orders: :product_orders) # table also when it is a real array :)
render json: json_response(not_present: true) and return unless list.present?
render json: list, serializer: UserExtendedListSerializer
end end
def show def show
list = List.find(params[:id]) @list ||= List.find(params[:id])
render json: {}, status: :not_found and return unless list.present? && Array.wrap(list.user_ids).include?(current_user.id) render json: {}, status: :not_found and return unless @list.present? && Array.wrap(@list.user_ids).include?(current_user.id)
[list].include_relation(supplier: {product_categories: :products}, orders: :product_orders) # table also when it is a real array :) [@list].include_relation(:users)
render json: list, serializer: UserExtendedListSerializer render json: @list, serializer: Users::ListSerializer, include: %w[supplier users]
end end
end end
end end
+10 -1
View File
@@ -2,6 +2,15 @@ module Users
class OrdersController < Users::ApplicationController class OrdersController < Users::ApplicationController
respond_to :json respond_to :json
# /nested resource
def index
render json: {}, status: :not_found and return unless params[:list_id].present?
@list = List.find(params[:list_id])
render json: {}, status: :not_found and return unless @list.present? && Array.wrap(@list.user_ids).include?(current_user.id)
orders = @list.orders.include_relation(:product_orders)
render json: orders, each_serializer: Users::OrderSerializer, include: %w[product_orders]
end
# Used by the user Ember app # Used by the user Ember app
# POST /user/orders # POST /user/orders
def create def create
@@ -25,7 +34,7 @@ module Users
list = List.from_table( table, current_user ) list = List.from_table( table, current_user )
end end
order = list.place_order product_orders: params[:product_orders], user: current_user order = list.place_order product_orders: params[:product_orders], user: current_user
render json: order, serializer: OrderSerializer render json: order, serializer: Users::OrderSerializer
#render nothing: true #render nothing: true
end end
end end
+1 -1
View File
@@ -2,7 +2,7 @@ module Users
class TablesController < Users::ApplicationController class TablesController < Users::ApplicationController
def show def show
@table = Table.find(params[:id]) @table = Table.find(params[:id])
render json: @table, serializer: UserExtendedTableSerializer render json: @table, serializer: Users::TableSerializer
end end
end end
end end
+2 -2
View File
@@ -307,10 +307,10 @@ class List
# broadcast_users 'new_order', order: order.with_products_as_json, total_amount: price # broadcast_users 'new_order', order: order.with_products_as_json, total_amount: price
broadcast_users 'new_order', UserExtendedListSerializer.new(order.list).as_json broadcast_users 'new_order', Users::OrderSerializer.new(order).as_json
# broadcast_users 'orders_placed_count', count: orders_placed_count # broadcast_users 'orders_placed_count', count: orders_placed_count
broadcast_supplier supplier.id, 'list_update', SupplierListSerializer.new(self).as_json.merge(new_order_id: order.id) broadcast_supplier supplier.id, 'list_update', Supplier::ListSerializer.new(self).as_json.merge(new_order_id: order.id)
# broadcast_supplier supplier.id, 'new_order', OrderSerializer.new(order) # broadcast_supplier supplier.id, 'new_order', OrderSerializer.new(order)
broadcast_supplier supplier.id, 'orders_placed_count', count: orders_placed_count broadcast_supplier supplier.id, 'orders_placed_count', count: orders_placed_count
order order
+1 -1
View File
@@ -1,4 +1,4 @@
class JoinRequestSerializer < Qwaiter::Serializer class JoinRequestSerializer < Qwaiter::Serializer
attributes :list_id attributes :list_id
has_one :user, serializer: UserUserSerializer has_one :user, serializer: Users::UserSerializer
end end
+1 -1
View File
@@ -1,4 +1,4 @@
# Used for user ember1 # Used for user ember1
class ProductOrderSerializer < Qwaiter::Serializer class ProductOrderSerializer < Qwaiter::Serializer
attributes :order_id, :product_id, :quantity, :price, :product_name, :product_variant attributes :quantity, :price, :product_name, :product_variant
end end
@@ -21,9 +21,9 @@ class UserExtendedListSerializer < Qwaiter::Serializer
end end
has_many :orders has_many :orders
#has_many :product_categories #has_many :product_categories
has_one :table, serializer: UserExtendedTableSerializer # this one add a lot of stuff has_one :table, serializer: Users::TableSerializer # this one add a lot of stuff
has_many :join_requests, serializer: JoinRequestSerializer has_many :join_requests, serializer: JoinRequestSerializer
has_many :users, serializer: UserUserSerializer has_many :users, serializer: Users::UserSerializer
#has_one :supplier # added by other resource #has_one :supplier # added by other resource
def extended_version def extended_version
-20
View File
@@ -1,20 +0,0 @@
class UserListSerializer < Qwaiter::Serializer
# user ids for facebook pictures
attributes :state, :needs_help, :needs_payment, :user_requests_closing,
:is_paid, :price, :table_id, :table_number, :section_id, :user_ids,
:cached_supplier_name, :closed_at, :supplier_id, :extended_version
#def has_active_orders
#object.has_active_orders?
#end
def cached_supplier_name
object.supplier.name
end
def extended_version
false
end
# has_many :users, serializer: UserUserSerializer
# has_many :orders
# has_one :supplier, serializer: UserSupplierSerializer
end
-4
View File
@@ -1,4 +0,0 @@
class UserTableSerializer < Qwaiter::Serializer
self.root = :table
attributes :number, :width, :height, :position_x, :position_y, :section_id, :occupied, :needs_help
end
+11
View File
@@ -0,0 +1,11 @@
class Users::ListSerializer < Qwaiter::Serializer
# user ids for facebook pictures
self.root = :list
attributes :state, :needs_help, :needs_payment, :user_requests_closing,
:is_paid, :price, :closed_at
has_many :users, serializer: Users::UserSerializer
has_many :orders, url: ->(list){ "/user/lists/#{list.id}/orders" }, serializer: OrderSerializer
has_one :supplier, serializer: Users::SupplierSerializer
#belongs_to :table
end
@@ -0,0 +1,8 @@
class Users::OrderSerializer < Qwaiter::Serializer
attributes :state #, :list_id, :section_id, :table_id #, :price
has_many :product_orders, serializer: Users::ProductOrderSerializer
belongs_to :list
#belongs_to :section
#belongs_to :table
end
@@ -0,0 +1,6 @@
# Used for user ember1
class Users::ProductOrderSerializer < Qwaiter::Serializer
attributes :quantity, :price, :product_name, :product_variant
# belongs_to :product #DO NOT USE THIS, THIS IS NOT NEEDED
belongs_to :order
end
@@ -1,4 +1,4 @@
class UserSupplierSerializer < Qwaiter::Serializer class Users::SupplierSerializer < Qwaiter::Serializer
self.root = :supplier self.root = :supplier
attributes :extended_version, :open, :name attributes :extended_version, :open, :name
+12
View File
@@ -0,0 +1,12 @@
class Users::TableSerializer < Qwaiter::Serializer
self.root = :table
attributes :number, :width, :height, :position_x, :position_y, :section_id, :occupied, :supplier_id #, :alist_id
#def list_id
#object.active_list_id || object.active_list.try(:id)
#end
#def list
#object.active_list
#end
end
@@ -1,4 +1,4 @@
class UserUserSerializer < Qwaiter::Serializer class Users::UserSerializer < Qwaiter::Serializer
self.root = :user self.root = :user
attributes :email, :provider, :uid, :name, :avatar attributes :email, :provider, :uid, :name, :avatar
+77 -3
View File
@@ -1,4 +1,78 @@
ActiveModel::Serializer.setup do |config| #ActiveModel::Serializer.setup do |config|
config.embed = :ids # config.embed = :ids
config.embed_in_root = true # config.embed_in_root = true
# config.adapter = :json_api
#end
module ActiveModel::SerializerSupport
def read_attribute_for_serialization(attr)
public_send attr
end
end end
class Qwaiter::JsonAdapter < ActiveModel::Serializer::Adapter::JsonApi
def add_resource_relationships(attrs, serializer, options = {})
options[:add_included] = options.fetch(:add_included, true)
serializer.class._associations.dup.each do |name, association_options| #do |name, association, opts|
next unless object = serializer.object
if association_options[:type] == :has_many
# todo check for object["#{name}_ids"]
association_value = association_options[:association_options][:url] ? [] : serializer.send(name)
association_serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options)
else
# Only load if the record has to be included anyway or no id value can be found
if include_assoc?(name)
association_value = serializer.send(name)
else
association_id = object["#{name}_id"]
association_class= name.to_s.classify.safe_constantize
if association_id && association_class
association_value = association_class.new(id: association_id)
else
association_value = serializer.send(name)
end
end
association_serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options)
end
if association_serializer_class
association_serializer = association_serializer_class.new(
association_value,
options.except(:serializer).merge(serializer.serializer_from_options(association_options))
)
elsif !association_value.nil? && !association_value.instance_of?(Object)
association_options[:association_options][:virtual_value] = association_value
end
opts = association_options[:association_options]
attrs[:relationships] ||= {}
if association_serializer.respond_to?(:each)
if opts[:url]
add_related(attrs, name, serializer.object, opts[:url])
else
add_relationships(attrs, name, association_serializer)
end
else
if opts[:virtual_value]
add_relationship(attrs, name, nil, opts[:virtual_value])
else
add_relationship(attrs, name, association_serializer)
end
end
if options[:add_included]
Array(association_serializer).each do |association|
add_included(name, association)
end
end
end
end
def add_related(resource, name, record, related)
related_url = related.is_a?(Proc) ? related.call(record) : related
resource[:relationships] ||= {}
resource[:relationships][name] ||= { links: {} }
resource[:relationships][name][:links][:related] = related_url
end
end
#ActiveModel::Serializer.config.adapter = :json_api
ActiveModel::Serializer.config.adapter = Qwaiter::JsonAdapter
+1
View File
@@ -82,6 +82,7 @@ Qwaiter::Application.routes.draw do
collection do collection do
get :current get :current
end end
resources :orders, only: [:index]
end end
resources :orders, only: [:create] resources :orders, only: [:create]
+22
View File
@@ -1,7 +1,14 @@
module Qwaiter module Qwaiter
class Serializer < ActiveModel::Serializer class Serializer < ActiveModel::Serializer
def self.root=(val)
ActiveSupport::Deprecation.new('1.0', 'Mozo')
end
def self.root(val)
ActiveSupport::Deprecation.new('1.0', 'Mozo')
end
# attribute :_id, key: :id # attribute :_id, key: :id
attributes :id, :created_at, :updated_at attributes :id, :created_at, :updated_at
# Bug in rails 4.1 serializing symbols in jsonify # Bug in rails 4.1 serializing symbols in jsonify
#def to_json(*args) #def to_json(*args)
#as_json.to_json(*args) #as_json.to_json(*args)
@@ -10,6 +17,21 @@ module Qwaiter
#def id #def id
#object._id #object._id
#end #end
def created_at
timestamp_attribute :created_at
end
def updated_at
timestamp_attribute :updated_at
end
private
def timestamp_attribute(attr)
timestamp = object.send(attr)
return nil unless timestamp
timestamp.iso8601
end
end end
end end
+1
View File
@@ -1,5 +1,6 @@
FactoryGirl.define do FactoryGirl.define do
factory :product_order do factory :product_order do
quantity 1
association :order association :order
association :product association :product
end end
@@ -0,0 +1,30 @@
require 'spec_helper'
describe Users::OrderSerializer do
let(:adapter){ ActiveModel::Serializer.config.adapter }
it "does not perform extra queries" do
l = create :list
o1 = create :order, list: l
create :product_order, order: o1
create :product_order, order: o1
o2 = create :order, list: l
create :product_order, order: o2
create :product_order, order: o2
list = List.find(l.id)
orders = list.orders.include_relation(:product_orders)
#expect{ object_as_json orders }.not_to exceed_query_limit 0
expect{ object_as_json orders }.not_to perform_any_queries
result = object_as_json(orders)
binding.pry
#result[:included].size.should eq 4
end
def object_as_json(obj)
serializer = if obj.is_a?(Array)
ActiveModel::Serializer::ArraySerializer.new(obj, serializer: described_class, add_included: true)
else
serializer = described_class.new(obj)
end
adapter.new(serializer, include: %w[product_orders]).as_json
end
end
+88
View File
@@ -0,0 +1,88 @@
$performed_queries = []
CouchRest.class_eval do
class << self
alias_method :old_get, :get
def get(uri, options={})
$performed_queries << {url: uri, options: options} if is_query_uri?(uri)
old_get(uri, options)
end
def is_query_uri?(uri)
return false if uri =~ /\/_design\/\w+$/ # request design doc
return false if uri =~ /\/_uuids/
true
end
end
end
# taken from: http://stackoverflow.com/questions/5490411/counting-the-number-of-queries-performed
RSpec::Matchers.define :exceed_query_limit do |expected|
match do |block|
query_count(&block) > expected
end
failure_message_when_negated do |actual|
extra_queries = $performed_queries[expected..-1].map{|q| q[:url]}.map do |q|
if q =~ /5984\/\w+\/[0-9a-f]{32}$/
info = q
begin
record = CouchRest.get(q)
if record.is_a?(SimplyStored::Couch)
info += " #{record.class.name}"
end
rescue
end
info
else
q
end
end
"Expected to run maximum #{expected} queries, got #{@executed_queries}\nExtra queries:\n - #{extra_queries.join("\n - ")}"
end
def query_count(&block)
$performed_queries = []
block.call
@executed_queries = $performed_queries.size
end
def supports_block_expectations?
true
end
end
RSpec::Matchers.define :perform_any_queries do |expected|
match do |block|
query_count(&block) > 0
end
failure_message_when_negated do |actual|
extra_queries = $performed_queries.map{|q| q[:url]}.map do |q|
if q =~ /5984\/\w+\/[0-9a-f]{32}$/
info = q
begin
record = CouchRest.get(q)
if record.is_a?(SimplyStored::Couch)
info += " #{record.class.name}"
end
rescue
end
info
else
q
end
end
"Expected to run no queries, got #{@executed_queries}\nExtra queries:\n - #{extra_queries.join("\n - ")}"
end
def query_count(&block)
$performed_queries = []
block.call
@executed_queries = $performed_queries.size
end
def supports_block_expectations?
true
end
end