diff --git a/Gemfile b/Gemfile index bede3470..b99b65de 100644 --- a/Gemfile +++ b/Gemfile @@ -15,7 +15,7 @@ gem 'slim-rails' # Gems used only for assets and not required # 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 gem 'jquery-rails' gem 'jquery-ui-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 7f4a32cc..a7864980 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -67,8 +67,8 @@ GEM activemodel (>= 3.0.2, < 5.0) activesupport (>= 3.0.2, < 5.0) active_decorator (0.5.3) - active_model_serializers (0.9.3) - activemodel (>= 3.2) + active_model_serializers (0.10.0.rc2) + activemodel (>= 4.0) activejob (4.2.4) activesupport (= 4.2.4) globalid (>= 0.3.0) @@ -236,7 +236,7 @@ GEM http_parser.rb (0.6.0) i18n (0.7.0) iso_country_codes (0.7.1) - jquery-rails (4.0.4) + jquery-rails (4.0.5) rails-dom-testing (~> 1.0) railties (>= 4.2.0) thor (>= 0.14, < 2.0) @@ -465,7 +465,7 @@ DEPENDENCIES ace-rails-ap active_attr active_decorator - active_model_serializers (~> 0.9.3) + active_model_serializers (~> 0.10.0.rc2) airbrussh bourbon cancancan diff --git a/app/assets/javascripts/user/app/components/lists/index-entry.js.coffee b/app/assets/javascripts/user/app/components/lists/index-entry.js.coffee index 4b71e877..16ce0989 100644 --- a/app/assets/javascripts/user/app/components/lists/index-entry.js.coffee +++ b/app/assets/javascripts/user/app/components/lists/index-entry.js.coffee @@ -1,4 +1,4 @@ -App.ListsIndexEntryComponent = Ember.Component.extend +App.ListIndexEntryComponent = Ember.Component.extend layoutName: 'lists/index-entry' classNames: ['lists-overview-entry'] classNameBindings: ['content.active:active'] diff --git a/app/assets/javascripts/user/app/components/menu/item/product_orders.js.coffee b/app/assets/javascripts/user/app/components/menu/item/product_orders.js.coffee index 973ade51..411540f5 100644 --- a/app/assets/javascripts/user/app/components/menu/item/product_orders.js.coffee +++ b/app/assets/javascripts/user/app/components/menu/item/product_orders.js.coffee @@ -4,7 +4,7 @@ App.MenuItemProductOrdersComponent = Ember.Component.extend layoutName: 'components/menu/product_orders' classNames: ['menu-list-item', 'menu-list-item-product-orders'] 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' orderTotal: Ember.computed.sum 'orderTotals' #orderTotal: Ember.computed 'product_orders.@each.total', -> diff --git a/app/assets/javascripts/user/app/components/menu_item_list_needs_help.js.coffee b/app/assets/javascripts/user/app/components/menu_item_list_needs_help.js.coffee index 5585bf59..1d7e5bc0 100644 --- a/app/assets/javascripts/user/app/components/menu_item_list_needs_help.js.coffee +++ b/app/assets/javascripts/user/app/components/menu_item_list_needs_help.js.coffee @@ -2,9 +2,9 @@ App.MenuItemListNeedsHelpComponent = Ember.Component.extend Ember.ViewTargetActi action: 'listNeedsHelp' layoutName: "components/menu/list_needs_help" classNames: 'menu-list-item callout' - classNameBindings: ['globals.list.needs_help:active'] + classNameBindings: ['globals.active_list.needs_help:active'] 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') else @triggerAction() diff --git a/app/assets/javascripts/user/app/components/menu_item_list_needs_payment.js.coffee b/app/assets/javascripts/user/app/components/menu_item_list_needs_payment.js.coffee index ccaf0f18..56a5ca87 100644 --- a/app/assets/javascripts/user/app/components/menu_item_list_needs_payment.js.coffee +++ b/app/assets/javascripts/user/app/components/menu_item_list_needs_payment.js.coffee @@ -2,9 +2,9 @@ App.MenuItemListNeedsPaymentComponent = Ember.Component.extend Ember.ViewTargetA action: 'listNeedsPayment' layoutName: "components/menu/list_needs_payment" classNames: 'menu-list-item callout' - classNameBindings: ['controller.list.needs_payment:active'] + classNameBindings: ['globals.active_list.needs_payment:active'] click: -> - if @get('controller.list.needs_payment') + if @get('globals.active_list.needs_payment') @set 'globals.notice', t('list_needs_payment.payment_already_requested') else @triggerAction() #action: 'listNeedsPayment' diff --git a/app/assets/javascripts/user/app/components/new-product-orders-list.js.coffee b/app/assets/javascripts/user/app/components/new-product-orders-list.js.coffee index 0704e263..24a14135 100644 --- a/app/assets/javascripts/user/app/components/new-product-orders-list.js.coffee +++ b/app/assets/javascripts/user/app/components/new-product-orders-list.js.coffee @@ -14,14 +14,14 @@ App.NewProductOrdersListComponent = Ember.Component.extend # @get('product_orders').invoke 'eraseRecord' orderProducts: -> # table = @get('controllers.table.model') - # list = @get('globals.list') + # list = @get('globals.active_list') # order = @store.createRecord('order', list: list, table: table) # new_product_orders = @store.all('product_order').filterProperty('order', null) # order.get('product_orders').pushObjects(new_product_orders) # # order.save().then (response)=> # new_product_orders.invoke 'eraseRecord' - # if @get('globals.list') + # if @get('globals.active_list') # @transitionToRoute 'active_list' # else # # Get list info from the server diff --git a/app/assets/javascripts/user/app/controllers/active_list_controller.js.coffee b/app/assets/javascripts/user/app/controllers/active_list_controller.js.coffee index dba75e96..7fe7d2ad 100644 --- a/app/assets/javascripts/user/app/controllers/active_list_controller.js.coffee +++ b/app/assets/javascripts/user/app/controllers/active_list_controller.js.coffee @@ -2,4 +2,4 @@ App.ActiveListController = Ember.Controller.extend #orders: (-> #@get('list.orders') #).property('list.orders') - list: (-> @get('globals.list') ).property('globals.list') + list: Ember.computed.alias 'globals.active_list' diff --git a/app/assets/javascripts/user/app/controllers/application_controller.js.coffee b/app/assets/javascripts/user/app/controllers/application_controller.js.coffee index f45f6ca6..1652bab5 100644 --- a/app/assets/javascripts/user/app/controllers/application_controller.js.coffee +++ b/app/assets/javascripts/user/app/controllers/application_controller.js.coffee @@ -1,5 +1,4 @@ App.ApplicationController = Ember.Controller.extend - #list: Ember.computed.alias 'globals.list' #notice: '' actions: confirmCancel: -> @@ -10,7 +9,7 @@ App.ApplicationController = Ember.Controller.extend @set 'globals.notice', '' showSupplierStatusInfo: -> @modal 'supplier_status_info', - model: @get('globals.list.supplier') + model: @get('globals.active_list.supplier') title_path: 'supplier_status_info.title' openDebugger: -> @@ -21,14 +20,14 @@ App.ApplicationController = Ember.Controller.extend ).observes('currentPath') events: notify: (notification) -> @set 'globals.notice', notification.message - list_helped: -> @set 'globals.list.needs_help', false - list_needs_help: -> @set 'globals.list.needs_help', true # incoming from other users - list_is_paid: -> @set 'globals.list.needs_payment', false - list_needs_payment: -> @set 'globals.list.needs_payment', true # incoming from other users + list_helped: -> @set 'globals.active_list.needs_help', false + list_needs_help: -> @set 'globals.active_list.needs_help', true # incoming from other users + list_is_paid: -> @set 'globals.active_list.needs_payment', false + list_needs_payment: -> @set 'globals.active_list.needs_payment', true # incoming from other users list_closed: (data)-> @transitionToRoute('list', data.id).then => - @set 'globals.list.state', 'closed' - @set 'globals.list', null + @set 'globals.active_list.state', 'closed' + @set 'globals.active_list', null order_being_processed: (data)-> order = @store.all('order').findBy 'id', data.id order.set('state', 'active') if order @@ -65,7 +64,7 @@ App.ApplicationController = Ember.Controller.extend 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 @setCurrentList -> @transitionToRoute('active_list').then => @@ -73,16 +72,16 @@ App.ApplicationController = Ember.Controller.extend @set 'globals.join_request_sent', false 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)-> - @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)-> - @set 'globals.list.supplier.orders_placed_count', data.count + @set 'globals.active_list.supplier.orders_placed_count', data.count new_order: (data)-> # return if @store.all('order').findProperty('id', data.order.id) @store.pushPayload data - @store.findById('list', data.list.id).then (list)=> @set 'globals.list', list - # @store.findById('order', data.order.id).then (order)-> + @store.peekRecord('list', data.list.id).then (list)=> @set 'globals.active_list', list + # @store.peekRecord('order', data.order.id).then (order)-> # list = order.get('list') # list.get('orders').addObject(order) @@ -92,15 +91,16 @@ App.ApplicationController = Ember.Controller.extend list.set 'needs_payment', false setCurrentList: (callback)-> 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 # 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() #TODO: depricate list on application controller #@set 'list', list - @set 'globals.list', list + @set 'globals.active_list', list if list.get('join_requests.length') @transitionToRoute 'join_requests' else if @currentRouteName is 'index' @@ -112,7 +112,7 @@ App.ApplicationController = Ember.Controller.extend #console.log "Error: #{emberError.message}" if emberError.message if error_list = @store.peekRecord('list', 'current') error_list.eraseRecord() - @set 'globals.list', null + @set 'globals.active_list', null switch @currentRouteName when 'table' then # nothing else @redirect_to 'user_root' diff --git a/app/assets/javascripts/user/app/controllers/join_requests_controller.js.coffee b/app/assets/javascripts/user/app/controllers/join_requests_controller.js.coffee index a470c38c..86b2780b 100644 --- a/app/assets/javascripts/user/app/controllers/join_requests_controller.js.coffee +++ b/app/assets/javascripts/user/app/controllers/join_requests_controller.js.coffee @@ -1,5 +1,5 @@ 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: rejectRequest: (join_request)-> Ember.$.post("#{$data_host}/user/reject_join_request", user_id: join_request.get('user.id')).then (response)-> diff --git a/app/assets/javascripts/user/app/controllers/table_controller.js.coffee b/app/assets/javascripts/user/app/controllers/table_controller.js.coffee index 2ee64f50..bfb6cdf1 100644 --- a/app/assets/javascripts/user/app/controllers/table_controller.js.coffee +++ b/app/assets/javascripts/user/app/controllers/table_controller.js.coffee @@ -1,21 +1,19 @@ App.TableController = Ember.Controller.extend tableCanTakeOrders: (-> return false unless @get('supplier.can_take_orders') - list = @get('globals.list') - if list + if list = @get('globals.active_list') return false unless list.get('supplier.id') == @get('supplier.id') return false unless list.get('table.id') == @get('model.id') true else # no list and open supplier if @get('model.occupied') then false else true - ).property('globals.list.id', 'supplier.can_take_orders', 'model.occupied', 'model.id', 'globals.list.table.id') - supplier: Ember.computed 'model.supplier', -> @get('model.supplier') - showJoinButton: (-> + ).property('globals.active_list.id', 'supplier.can_take_orders', 'model.occupied', 'model.id', 'globals.active_list.table.id') + supplier: Ember.computed.alias 'model.supplier' + 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 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 - ).property('globals.list.id', 'supplier.can_take_orders', 'model.occupied', 'model.id', 'globals.list.table.id') actions: joinOccupiedTable: -> Ember.$.post("#{$data_host}/user/join_occupied_table.json", table_id: @get('model.id')) diff --git a/app/assets/javascripts/user/app/models/join_request.js.coffee b/app/assets/javascripts/user/app/models/join_request.js.coffee index 1f31d669..159e8b95 100644 --- a/app/assets/javascripts/user/app/models/join_request.js.coffee +++ b/app/assets/javascripts/user/app/models/join_request.js.coffee @@ -1,4 +1,4 @@ attr = DS.attr App.JoinRequest= DS.Model.extend - list: DS.belongsTo('list') - user: DS.belongsTo('user') + list: DS.belongsTo('list', async: false) + user: DS.belongsTo('user', async: false) diff --git a/app/assets/javascripts/user/app/models/list.js.coffee b/app/assets/javascripts/user/app/models/list.js.coffee index 7853fae0..d60fea53 100644 --- a/app/assets/javascripts/user/app/models/list.js.coffee +++ b/app/assets/javascripts/user/app/models/list.js.coffee @@ -1,31 +1,31 @@ attr = DS.attr App.List = DS.Model.extend - orders: DS.hasMany('order') - needs_help: attr('boolean') - needs_payment: attr('boolean') - user_requests_closing: attr('boolean') + needs_help: attr('boolean', defaultValue: false) + needs_payment: attr('boolean', defaultValue: false) + user_requests_closing: attr('boolean', defaultValue: false) state: attr('string') price: attr('number') - closed_at: DS.attr('date') + closed_at: attr('date') extended_version: attr('boolean') supplier_orders_in_process_count: attr('number') supplier_orders_placed_count: attr('number') - cached_supplier_name: attr('string') - supplier: DS.belongsTo('supplier') - table: DS.belongsTo('table') - join_requests: DS.hasMany('join_request') - users: DS.hasMany('user') + orders: DS.hasMany('order', async: true) + supplier: DS.belongsTo('supplier', async: false) + table: DS.belongsTo('table', async: true) + join_requests: DS.hasMany('join_request', async: false) + users: DS.hasMany('user', async: false) is_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') total: (-> @get('relevant_orders').getEach('total').reduce(((sum, total) -> sum + total), 0) ).property('relevant_orders.@each.total') - active: (-> @get('state') is 'active' ).property('state') + active: Ember.computed.equal 'state', 'active' - showTotal: (-> - if @get('orders.length') && @get('orders.length') > 1 then true else false - ).property('orders.length') + #showTotal: (-> + # if @get('orders.length') && @get('orders.length') > 1 then true else false + #).property('orders.length') + showTotal: Ember.computed.gt 'relevant_orders.length', 1 diff --git a/app/assets/javascripts/user/app/models/order.js.coffee b/app/assets/javascripts/user/app/models/order.js.coffee index 1e64bfef..0675f2c7 100644 --- a/app/assets/javascripts/user/app/models/order.js.coffee +++ b/app/assets/javascripts/user/app/models/order.js.coffee @@ -1,9 +1,9 @@ attr = DS.attr App.Order = DS.Model.extend state: attr 'string' - list: DS.belongsTo('list') + list: DS.belongsTo('list', async: true) table: DS.belongsTo('table') - product_orders: DS.hasMany('product_order', embedded: 'always') + product_orders: DS.hasMany('product_order', async: false) total: (-> @get('product_orders').getEach('total').reduce(((sum, total) -> sum + total), 0) ).property('product_orders.@each.quantity') diff --git a/app/assets/javascripts/user/app/models/product_order.js.coffee b/app/assets/javascripts/user/app/models/product_order.js.coffee index dfee1518..202d8e5d 100644 --- a/app/assets/javascripts/user/app/models/product_order.js.coffee +++ b/app/assets/javascripts/user/app/models/product_order.js.coffee @@ -2,16 +2,16 @@ attr = DS.attr App.ProductOrder = DS.Model.extend quantity: attr 'number', defaultValue: 1 price: attr 'number' - product_name: attr('string') - product: DS.belongsTo('product') + product_name: 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 + product: DS.belongsTo('product', async: true) + order: DS.belongsTo('order', async: false) increment: -> @set('quantity', @get('quantity') + 1) total: (-> @get('quantity') * @get('price')).property('quantity', 'price') - display: Ember.computed 'quantity', 'product_variant', 'product.name', -> - disp = "#{@get('quantity')} x #{@get('product.name')}" + display: Ember.computed 'quantity', 'product_variant', 'product_name', -> + disp = "#{@get('quantity')} x #{@get('product_name')}" if variant = @get('product_variant') disp = "#{disp} (#{variant})" disp.htmlSafe() diff --git a/app/assets/javascripts/user/app/models/supplier.js.coffee b/app/assets/javascripts/user/app/models/supplier.js.coffee index 47cc46d1..6f0beb14 100644 --- a/app/assets/javascripts/user/app/models/supplier.js.coffee +++ b/app/assets/javascripts/user/app/models/supplier.js.coffee @@ -7,8 +7,8 @@ App.Supplier= DS.Model.extend orders_placed_count: attr('number') orders: DS.hasMany('order') - product_categories: DS.hasMany('product_category') - lists: DS.hasMany('list') + product_categories: DS.hasMany('product_category', async: true) + lists: DS.hasMany('list', async: true) is_extended_version: -> @get('extended_version') diff --git a/app/assets/javascripts/user/app/models/table.js.coffee b/app/assets/javascripts/user/app/models/table.js.coffee index 4c476505..56b08d87 100644 --- a/app/assets/javascripts/user/app/models/table.js.coffee +++ b/app/assets/javascripts/user/app/models/table.js.coffee @@ -4,4 +4,4 @@ App.Table= DS.Model.extend needs_help: attr('boolean') occupied: attr('boolean') - supplier: DS.belongsTo('supplier') + supplier: DS.belongsTo('supplier', async: true) diff --git a/app/assets/javascripts/user/app/modifications/model_modifications.js.coffee b/app/assets/javascripts/user/app/modifications/model_modifications.js.coffee index 31ca208c..1576b59e 100644 --- a/app/assets/javascripts/user/app/modifications/model_modifications.js.coffee +++ b/app/assets/javascripts/user/app/modifications/model_modifications.js.coffee @@ -1,6 +1,6 @@ DS.Model.reopen - created_at: DS.attr('date') - updated_at: DS.attr('date') + #created_at: DS.attr('date') + #updated_at: DS.attr('date') eraseRecord: -> #@clearRelationships() @transitionTo('deleted.saved') diff --git a/app/assets/javascripts/user/app/routes/active_list_route.js.coffee b/app/assets/javascripts/user/app/routes/active_list_route.js.coffee index 8c74f9e6..ca062609 100644 --- a/app/assets/javascripts/user/app/routes/active_list_route.js.coffee +++ b/app/assets/javascripts/user/app/routes/active_list_route.js.coffee @@ -1,6 +1,6 @@ App.ActiveListRoute = Ember.Route.extend App.ResetScroll #model: -> - #@get('globals.list') + #@get('globals.active_list') #afterModel: -> #controller = @controllerFor('application') #table_id = controller.get('list.table.id') diff --git a/app/assets/javascripts/user/app/routes/application_route.js.coffee.erb b/app/assets/javascripts/user/app/routes/application_route.js.coffee.erb index 491c3e73..3752b4d1 100644 --- a/app/assets/javascripts/user/app/routes/application_route.js.coffee.erb +++ b/app/assets/javascripts/user/app/routes/application_route.js.coffee.erb @@ -13,7 +13,7 @@ App.ApplicationRoute = Ember.Route.extend unauthorized: -> Qstorage.removeItem('auth_token') Qstorage.removeItem('user_id') - @set 'globals.list', null + @set 'globals.active_list', null #@send 'obtain_token' @controllerFor('application').redirect_to 'sign_in', message: 'unauthorized' @@ -76,13 +76,13 @@ App.ApplicationRoute = Ember.Route.extend listNeedsPayment: -> @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").then (res) => #@set('list.needs_payment', true) # also done by faye listNeedsHelp: -> @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").then (res) => #@set('list.needs_help', true) # also done by faye diff --git a/app/assets/javascripts/user/app/routes/list_route.js.coffee b/app/assets/javascripts/user/app/routes/list_route.js.coffee index 9fe14bb0..8c1c5486 100644 --- a/app/assets/javascripts/user/app/routes/list_route.js.coffee +++ b/app/assets/javascripts/user/app/routes/list_route.js.coffee @@ -1,5 +1,5 @@ App.ListRoute = Ember.Route.extend App.ResetScroll, model: (options)-> - @store.find 'list', options.list_id + @store.findRecord 'list', options.list_id afterModel: (model)-> model.reload() unless model.is_extended_version() diff --git a/app/assets/javascripts/user/app/routes/lists_route.js.coffee b/app/assets/javascripts/user/app/routes/lists_route.js.coffee index 522742fe..fbef2cb2 100644 --- a/app/assets/javascripts/user/app/routes/lists_route.js.coffee +++ b/app/assets/javascripts/user/app/routes/lists_route.js.coffee @@ -1,5 +1,5 @@ App.ListsRoute = Ember.Route.extend App.ResetScroll, model: -> - @store.find 'list' + @store.findAll 'list' setupController: (controller, model)-> controller.set('alreadyLoaded', true) diff --git a/app/assets/javascripts/user/app/store.js.coffee b/app/assets/javascripts/user/app/store.js.coffee index 3b9d9cfe..1e32e010 100644 --- a/app/assets/javascripts/user/app/store.js.coffee +++ b/app/assets/javascripts/user/app/store.js.coffee @@ -1,7 +1,10 @@ -App.ApplicationSerializer = DS.ActiveModelSerializer.extend() -App.ApplicationAdapter = DS.ActiveModelAdapter.extend +#App.ApplicationSerializer = DS.ActiveModelSerializer.extend() +App.ApplicationSerializer = DS.JSONAPISerializer.extend + keyForAttribute: (attr, method)-> attr +#App.ApplicationAdapter = DS.ActiveModelAdapter.extend +App.ApplicationAdapter = DS.JSONAPIAdapter.extend host: $data_host namespace: 'user' - headers: - "Accept": "application/json, text/javascript; q=0.01" + #headers: + # "Accept": "application/json, text/javascript; q=0.01" diff --git a/app/assets/javascripts/user/app/templates/_list_content.emblem b/app/assets/javascripts/user/app/templates/_list_content.emblem index 5295431e..9db34172 100644 --- a/app/assets/javascripts/user/app/templates/_list_content.emblem +++ b/app/assets/javascripts/user/app/templates/_list_content.emblem @@ -13,7 +13,7 @@ if list.closed_at .display-row .display-label=t 'models.supplier' .display-field= list.supplier.name -if list.orders.isLoaded +if list.isLoaded if list.sorted_orders .list-orders-container each list.sorted_orders as |order| @@ -30,7 +30,7 @@ if list.orders.isLoaded span=t 'active_list.no_orders_explanation' br if list.table - link-to 'table' list.table class="button" + = link-to 'table' list.table class="button" span=t 'list_products.title' else span.loading.large diff --git a/app/assets/javascripts/user/app/templates/active_list.emblem b/app/assets/javascripts/user/app/templates/active_list.emblem index 67a30643..44534780 100644 --- a/app/assets/javascripts/user/app/templates/active_list.emblem +++ b/app/assets/javascripts/user/app/templates/active_list.emblem @@ -1,13 +1,13 @@ .row h2=t 'active_list.title' - if list.orders.isLoaded + if list.isLoaded if list partial "list_content" else p span=t 'active_list.not_active.message' br - link-to 'index' class="button" + = link-to 'index' class="button" span= t 'active_list.not_active.home_button_text' else span.loading.large diff --git a/app/assets/javascripts/user/app/templates/global/_side_menu.emblem b/app/assets/javascripts/user/app/templates/global/_side_menu.emblem index 474efd2c..11ddd0b9 100644 --- a/app/assets/javascripts/user/app/templates/global/_side_menu.emblem +++ b/app/assets/javascripts/user/app/templates/global/_side_menu.emblem @@ -9,9 +9,9 @@ a{action "scanQr" bubbles=false} span.scan-qr-icon span Scan QR - if globals.list.id + if globals.active_list.id 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-glass = t 'list_products.title' @@ -19,7 +19,7 @@ =link-to 'active_list' class="side-menu-active-list" span.active-list-icon span= t 'active_list.title' - if globals.list.join_requests.length + if globals.active_list.join_requests.length li =link-to 'join_requests' span= t 'models.plural.join_request' diff --git a/app/assets/javascripts/user/app/templates/global/_top_menu.emblem b/app/assets/javascripts/user/app/templates/global/_top_menu.emblem index 94121cef..0e0d4678 100644 --- a/app/assets/javascripts/user/app/templates/global/_top_menu.emblem +++ b/app/assets/javascripts/user/app/templates/global/_top_menu.emblem @@ -2,11 +2,11 @@ .top-menu-bar .menu-content section.main-buttons - if globals.list.id + if globals.active_list.id link-to 'index' class="top-menu-logo with-list" = image-tag 'user/logo-small.png' = 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-payment else @@ -14,18 +14,18 @@ = image-tag 'user/logo-small.png' = menu-item-scan-qr = menu-item-product-orders - if globals.list + if globals.active_list .extra-info{action "showSupplierStatusInfo"} .supplier-info-row / .supplier-name= list.supplier.name .table-number |#  - = globals.list.table.number + = globals.active_list.table.number .supplier-info-row .counter.supplier-orders-placed-count - = globals.list.supplier.orders_placed_count + = globals.active_list.supplier.orders_placed_count span.orders-placed-count-icon .supplier-info-row .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 diff --git a/app/assets/javascripts/user/app/templates/lists/index-entry.emblem b/app/assets/javascripts/user/app/templates/lists/index-entry.emblem index cfc5d299..7da66084 100644 --- a/app/assets/javascripts/user/app/templates/lists/index-entry.emblem +++ b/app/assets/javascripts/user/app/templates/lists/index-entry.emblem @@ -1,3 +1,3 @@ span.created_at=time list.created_at span.price.currency= currency list.price -span.name= list.cached_supplier_name +span.name= list.supplier.name diff --git a/app/assets/stylesheets/user/foundation/_qlists.sass b/app/assets/stylesheets/user/foundation/_qlists.sass index 31635e94..3f1cad77 100644 --- a/app/assets/stylesheets/user/foundation/_qlists.sass +++ b/app/assets/stylesheets/user/foundation/_qlists.sass @@ -24,6 +24,8 @@ .currency float: right margin-right: 0.5em + min-width: 60px + text-align: right .list-order-container background-position: left center background-repeat: no-repeat diff --git a/app/controllers/users/lists/orders_controller.rb b/app/controllers/users/lists/orders_controller.rb new file mode 100644 index 00000000..5c23c366 --- /dev/null +++ b/app/controllers/users/lists/orders_controller.rb @@ -0,0 +1,7 @@ +module Users + module Lists + class OrdersController < Users::ApplicationController + respond_to :json + end + end +end diff --git a/app/controllers/users/lists_controller.rb b/app/controllers/users/lists_controller.rb index f245ad24..777b801f 100644 --- a/app/controllers/users/lists_controller.rb +++ b/app/controllers/users/lists_controller.rb @@ -7,24 +7,21 @@ module Users #lists.include_relation(:supplier) 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.include_relation(:users, :orders, :supplier) - render json: lists, each_serializer: UserListSerializer, meta: {total_pages: lists.total_pages, page: lists.current_page} #, root: :lists + lists.include_relation(:users, :supplier) + render json: lists, each_serializer: Users::ListSerializer, meta: {total_pages: lists.total_pages, page: lists.current_page} #, root: :lists end #EMBER def current - list = current_user.active_list - render json: {}, status: :not_found and return unless list.present? - [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 + @list = current_user.active_list + show end def show - list = List.find(params[: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 :) - render json: list, serializer: UserExtendedListSerializer + @list ||= List.find(params[:id]) + render json: {}, status: :not_found and return unless @list.present? && Array.wrap(@list.user_ids).include?(current_user.id) + [@list].include_relation(:users) + render json: @list, serializer: Users::ListSerializer, include: %w[supplier users] end end end diff --git a/app/controllers/users/orders_controller.rb b/app/controllers/users/orders_controller.rb index 86067cb1..1d089364 100644 --- a/app/controllers/users/orders_controller.rb +++ b/app/controllers/users/orders_controller.rb @@ -2,6 +2,15 @@ module Users class OrdersController < Users::ApplicationController 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 # POST /user/orders def create @@ -25,7 +34,7 @@ module Users list = List.from_table( table, current_user ) end 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 end end diff --git a/app/controllers/users/tables_controller.rb b/app/controllers/users/tables_controller.rb index b582e2f8..bb10f00b 100644 --- a/app/controllers/users/tables_controller.rb +++ b/app/controllers/users/tables_controller.rb @@ -2,7 +2,7 @@ module Users class TablesController < Users::ApplicationController def show @table = Table.find(params[:id]) - render json: @table, serializer: UserExtendedTableSerializer + render json: @table, serializer: Users::TableSerializer end end end diff --git a/app/models/list.rb b/app/models/list.rb index 1d5ab520..8d00aa3a 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -307,10 +307,10 @@ class List # 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_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, 'orders_placed_count', count: orders_placed_count order diff --git a/app/serializers/join_request_serializer.rb b/app/serializers/join_request_serializer.rb index 6d018a12..8eda2de8 100644 --- a/app/serializers/join_request_serializer.rb +++ b/app/serializers/join_request_serializer.rb @@ -1,4 +1,4 @@ class JoinRequestSerializer < Qwaiter::Serializer attributes :list_id - has_one :user, serializer: UserUserSerializer + has_one :user, serializer: Users::UserSerializer end diff --git a/app/serializers/product_order_serializer.rb b/app/serializers/product_order_serializer.rb index 38990d3f..9d2c11b8 100644 --- a/app/serializers/product_order_serializer.rb +++ b/app/serializers/product_order_serializer.rb @@ -1,4 +1,4 @@ # Used for user ember1 class ProductOrderSerializer < Qwaiter::Serializer - attributes :order_id, :product_id, :quantity, :price, :product_name, :product_variant + attributes :quantity, :price, :product_name, :product_variant end diff --git a/app/serializers/user_extended_list_serializer.rb b/app/serializers/user_extended_list_serializer.rb index 4612eb68..6eea9d05 100644 --- a/app/serializers/user_extended_list_serializer.rb +++ b/app/serializers/user_extended_list_serializer.rb @@ -21,9 +21,9 @@ class UserExtendedListSerializer < Qwaiter::Serializer end has_many :orders #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 :users, serializer: UserUserSerializer + has_many :users, serializer: Users::UserSerializer #has_one :supplier # added by other resource def extended_version diff --git a/app/serializers/user_list_serializer.rb b/app/serializers/user_list_serializer.rb deleted file mode 100644 index 04d9442d..00000000 --- a/app/serializers/user_list_serializer.rb +++ /dev/null @@ -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 diff --git a/app/serializers/user_table_serializer.rb b/app/serializers/user_table_serializer.rb deleted file mode 100644 index dfef5799..00000000 --- a/app/serializers/user_table_serializer.rb +++ /dev/null @@ -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 diff --git a/app/serializers/users/list_serializer.rb b/app/serializers/users/list_serializer.rb new file mode 100644 index 00000000..29104952 --- /dev/null +++ b/app/serializers/users/list_serializer.rb @@ -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 diff --git a/app/serializers/users/order_serializer.rb b/app/serializers/users/order_serializer.rb new file mode 100644 index 00000000..9c14cb0a --- /dev/null +++ b/app/serializers/users/order_serializer.rb @@ -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 diff --git a/app/serializers/users/product_order_serializer.rb b/app/serializers/users/product_order_serializer.rb new file mode 100644 index 00000000..e96915c0 --- /dev/null +++ b/app/serializers/users/product_order_serializer.rb @@ -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 diff --git a/app/serializers/user_supplier_serializer.rb b/app/serializers/users/supplier_serializer.rb similarity index 67% rename from app/serializers/user_supplier_serializer.rb rename to app/serializers/users/supplier_serializer.rb index 7700dcd7..c2e3f25c 100644 --- a/app/serializers/user_supplier_serializer.rb +++ b/app/serializers/users/supplier_serializer.rb @@ -1,4 +1,4 @@ -class UserSupplierSerializer < Qwaiter::Serializer +class Users::SupplierSerializer < Qwaiter::Serializer self.root = :supplier attributes :extended_version, :open, :name diff --git a/app/serializers/users/table_serializer.rb b/app/serializers/users/table_serializer.rb new file mode 100644 index 00000000..f9109d35 --- /dev/null +++ b/app/serializers/users/table_serializer.rb @@ -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 diff --git a/app/serializers/user_user_serializer.rb b/app/serializers/users/user_serializer.rb similarity index 70% rename from app/serializers/user_user_serializer.rb rename to app/serializers/users/user_serializer.rb index d7b4ed5c..b0602a4c 100644 --- a/app/serializers/user_user_serializer.rb +++ b/app/serializers/users/user_serializer.rb @@ -1,4 +1,4 @@ -class UserUserSerializer < Qwaiter::Serializer +class Users::UserSerializer < Qwaiter::Serializer self.root = :user attributes :email, :provider, :uid, :name, :avatar diff --git a/config/initializers/active_model_serializer.rb b/config/initializers/active_model_serializer.rb index b7d9c1ca..ea75d3be 100644 --- a/config/initializers/active_model_serializer.rb +++ b/config/initializers/active_model_serializer.rb @@ -1,4 +1,78 @@ -ActiveModel::Serializer.setup do |config| - config.embed = :ids - config.embed_in_root = true +#ActiveModel::Serializer.setup do |config| +# config.embed = :ids +# config.embed_in_root = true +# config.adapter = :json_api +#end +module ActiveModel::SerializerSupport + def read_attribute_for_serialization(attr) + public_send attr + 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 diff --git a/config/routes.rb b/config/routes.rb index 958ee333..6812dc4a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -82,6 +82,7 @@ Qwaiter::Application.routes.draw do collection do get :current end + resources :orders, only: [:index] end resources :orders, only: [:create] diff --git a/lib/qwaiter/serializer.rb b/lib/qwaiter/serializer.rb index 94698a9b..15175c3b 100644 --- a/lib/qwaiter/serializer.rb +++ b/lib/qwaiter/serializer.rb @@ -1,7 +1,14 @@ module Qwaiter 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 attributes :id, :created_at, :updated_at + # Bug in rails 4.1 serializing symbols in jsonify #def to_json(*args) #as_json.to_json(*args) @@ -10,6 +17,21 @@ module Qwaiter #def id #object._id #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 diff --git a/spec/factories/product_order_factory.rb b/spec/factories/product_order_factory.rb index 1b2b06bb..a44871d4 100644 --- a/spec/factories/product_order_factory.rb +++ b/spec/factories/product_order_factory.rb @@ -1,5 +1,6 @@ FactoryGirl.define do factory :product_order do + quantity 1 association :order association :product end diff --git a/spec/serializers/users/order_serializer.rb b/spec/serializers/users/order_serializer.rb new file mode 100644 index 00000000..a1525d90 --- /dev/null +++ b/spec/serializers/users/order_serializer.rb @@ -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 diff --git a/spec/support/query_limit.rb b/spec/support/query_limit.rb new file mode 100644 index 00000000..4a92e2df --- /dev/null +++ b/spec/support/query_limit.rb @@ -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