voluntary_ranking 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +29 -0
  5. data/app/assets/javascripts/voluntary_ranking/app.js +11 -0
  6. data/app/assets/javascripts/voluntary_ranking/application.js +4 -0
  7. data/app/assets/javascripts/voluntary_ranking/base.js.coffee +3 -0
  8. data/app/assets/javascripts/voluntary_ranking/components/modal_dialog_component.js.coffee +6 -0
  9. data/app/assets/javascripts/voluntary_ranking/controllers/arguments/index_controller.js.coffee +5 -0
  10. data/app/assets/javascripts/voluntary_ranking/controllers/arguments/new_controller.js.coffee +16 -0
  11. data/app/assets/javascripts/voluntary_ranking/controllers/compare_things/arguments_controller.js.coffee +5 -0
  12. data/app/assets/javascripts/voluntary_ranking/controllers/compare_things_controller.js.coffee +8 -0
  13. data/app/assets/javascripts/voluntary_ranking/controllers/controller.js.coffee +1 -0
  14. data/app/assets/javascripts/voluntary_ranking/controllers/index_controller.js.coffee +5 -0
  15. data/app/assets/javascripts/voluntary_ranking/controllers/profile/rankings_controller.js.coffee +3 -0
  16. data/app/assets/javascripts/voluntary_ranking/controllers/ranking_item_controller.js.coffee +7 -0
  17. data/app/assets/javascripts/voluntary_ranking/controllers/rankings/index_controller.js.coffee +5 -0
  18. data/app/assets/javascripts/voluntary_ranking/controllers/rankings/show_controller.js.coffee +6 -0
  19. data/app/assets/javascripts/voluntary_ranking/controllers/thing_controller.js.coffee +10 -0
  20. data/app/assets/javascripts/voluntary_ranking/controllers/user/rankings/show_controller.js.coffee +92 -0
  21. data/app/assets/javascripts/voluntary_ranking/controllers/user_controller.js.coffee +5 -0
  22. data/app/assets/javascripts/voluntary_ranking/controllers/user_ranking_controller.js.coffee +2 -0
  23. data/app/assets/javascripts/voluntary_ranking/helpers/name_with_apostrophe_helper.js.coffee +5 -0
  24. data/app/assets/javascripts/voluntary_ranking/helpers/stars_html_helper.js.coffee +29 -0
  25. data/app/assets/javascripts/voluntary_ranking/mixins/has_current_user.js.coffee +4 -0
  26. data/app/assets/javascripts/voluntary_ranking/mixins/pagination_controller.js.coffee +51 -0
  27. data/app/assets/javascripts/voluntary_ranking/mixins/ranking_controller.js.coffee +31 -0
  28. data/app/assets/javascripts/voluntary_ranking/mixins/singleton.js.coffee +17 -0
  29. data/app/assets/javascripts/voluntary_ranking/models/argument.js.coffee +7 -0
  30. data/app/assets/javascripts/voluntary_ranking/models/movie.js.coffee +5 -0
  31. data/app/assets/javascripts/voluntary_ranking/models/ranking.js.coffee +5 -0
  32. data/app/assets/javascripts/voluntary_ranking/models/ranking_item.js.coffee +26 -0
  33. data/app/assets/javascripts/voluntary_ranking/models/thing.js.coffee +2 -0
  34. data/app/assets/javascripts/voluntary_ranking/models/user.js.coffee +18 -0
  35. data/app/assets/javascripts/voluntary_ranking/models/user/ranking_item.js.coffee +33 -0
  36. data/app/assets/javascripts/voluntary_ranking/router.js.coffee +30 -0
  37. data/app/assets/javascripts/voluntary_ranking/routes/arguments/index_route.js.coffee +24 -0
  38. data/app/assets/javascripts/voluntary_ranking/routes/compare_things/arguments_route.js.coffee +16 -0
  39. data/app/assets/javascripts/voluntary_ranking/routes/compare_things/compare_things_route.js.coffee +9 -0
  40. data/app/assets/javascripts/voluntary_ranking/routes/profile/rankings_route.js.coffee +29 -0
  41. data/app/assets/javascripts/voluntary_ranking/routes/ranking_item_route.js.coffee +25 -0
  42. data/app/assets/javascripts/voluntary_ranking/routes/rankings/index_route.js.coffee +10 -0
  43. data/app/assets/javascripts/voluntary_ranking/routes/rankings/show_route.js.coffee +19 -0
  44. data/app/assets/javascripts/voluntary_ranking/routes/thing_route.js.coffee +7 -0
  45. data/app/assets/javascripts/voluntary_ranking/routes/user_ranking_route.js.coffee +27 -0
  46. data/app/assets/javascripts/voluntary_ranking/routes/user_route.js.coffee +20 -0
  47. data/app/assets/javascripts/voluntary_ranking/templates/application.handlebars.erb +16 -0
  48. data/app/assets/javascripts/voluntary_ranking/templates/arguments.js.handlebars +1 -0
  49. data/app/assets/javascripts/voluntary_ranking/templates/arguments/index.js.handlebars +27 -0
  50. data/app/assets/javascripts/voluntary_ranking/templates/arguments/new.js.handlebars +17 -0
  51. data/app/assets/javascripts/voluntary_ranking/templates/compare_things.js.handlebars +22 -0
  52. data/app/assets/javascripts/voluntary_ranking/templates/compare_things/arguments.js.handlebars +26 -0
  53. data/app/assets/javascripts/voluntary_ranking/templates/components/modal-dialog.js.handlebars +9 -0
  54. data/app/assets/javascripts/voluntary_ranking/templates/components/rankings-component.handlebars +17 -0
  55. data/app/assets/javascripts/voluntary_ranking/templates/index.js.handlebars +1 -0
  56. data/app/assets/javascripts/voluntary_ranking/templates/navigation.js.handlebars +28 -0
  57. data/app/assets/javascripts/voluntary_ranking/templates/ranking_item.js.handlebars +31 -0
  58. data/app/assets/javascripts/voluntary_ranking/templates/ranking_items/_collection.js.handlebars +84 -0
  59. data/app/assets/javascripts/voluntary_ranking/templates/ranking_items/_form.js.handlebars +30 -0
  60. data/app/assets/javascripts/voluntary_ranking/templates/rankings/_form.js.handlebars +38 -0
  61. data/app/assets/javascripts/voluntary_ranking/templates/rankings/index.js.handlebars +3 -0
  62. data/app/assets/javascripts/voluntary_ranking/templates/rankings/show.js.handlebars +3 -0
  63. data/app/assets/javascripts/voluntary_ranking/templates/shared/_pagination.js.handlebars +23 -0
  64. data/app/assets/javascripts/voluntary_ranking/templates/shared/_stars.js.handlebars +3 -0
  65. data/app/assets/javascripts/voluntary_ranking/templates/thing.js.handlebars +13 -0
  66. data/app/assets/javascripts/voluntary_ranking/templates/thing/index.js.handlebars +0 -0
  67. data/app/assets/javascripts/voluntary_ranking/templates/things/show.arguments.js.handlebars +1 -0
  68. data/app/assets/javascripts/voluntary_ranking/templates/things/show.js.handlebars +1 -0
  69. data/app/assets/javascripts/voluntary_ranking/templates/user.js.handlebars +5 -0
  70. data/app/assets/javascripts/voluntary_ranking/templates/user/rankings/details.js.handlebars +7 -0
  71. data/app/assets/javascripts/voluntary_ranking/views/application/index_view.js.coffee +1 -0
  72. data/app/assets/javascripts/voluntary_ranking/views/arguments/new_view.js.coffee +9 -0
  73. data/app/assets/javascripts/voluntary_ranking/views/index_view.js.coffee +1 -0
  74. data/app/assets/javascripts/voluntary_ranking/views/ranking_items/colllection_view.js.coffee +25 -0
  75. data/app/assets/javascripts/voluntary_ranking/views/shared/pagination.js +4 -0
  76. data/app/assets/stylesheets/voluntary_ranking/application.css +17 -0
  77. data/app/assets/stylesheets/voluntary_ranking/base.css.sass +6 -0
  78. data/app/assets/stylesheets/voluntary_ranking/bootstrap_and_overrides.css.sass +0 -0
  79. data/app/assets/stylesheets/voluntary_ranking/stars.css.sass +31 -0
  80. data/app/assets/stylesheets/voluntary_ranking/twitter-typeahead.css.sass +29 -0
  81. data/app/controllers/api/v1/argument_topics_controller.rb +12 -0
  82. data/app/controllers/api/v1/arguments_controller.rb +32 -0
  83. data/app/controllers/api/v1/ranking_items_controller.rb +43 -0
  84. data/app/controllers/api/v1/rankings_controller.rb +29 -0
  85. data/app/controllers/api/v1/things/arguments_controller.rb +40 -0
  86. data/app/controllers/api/v1/things_controller.rb +26 -0
  87. data/app/controllers/api/v1/user_ranking_items_controller.rb +94 -0
  88. data/app/controllers/api/v1/users_controller.rb +9 -0
  89. data/app/controllers/product/ranking_controller.rb +16 -0
  90. data/app/models/argument.rb +48 -0
  91. data/app/models/argument_topic.rb +7 -0
  92. data/app/models/product/ranking.rb +2 -0
  93. data/app/models/ranking.rb +97 -0
  94. data/app/models/ranking_item.rb +30 -0
  95. data/app/models/user_ranking_item.rb +136 -0
  96. data/app/serializers/argument_serializer.rb +11 -0
  97. data/app/serializers/base_ranking_item_serializer.rb +23 -0
  98. data/app/serializers/ranking_item_serializer.rb +2 -0
  99. data/app/serializers/user_ranking_item_serializer.rb +7 -0
  100. data/app/views/product/ranking/index.html.erb +0 -0
  101. data/config/locales/en.yml +10 -0
  102. data/config/locales/resources/ranking/en.yml +10 -0
  103. data/config/routes.rb +41 -0
  104. data/db/migrate/20130817115303_add_ranking_product.rb +50 -0
  105. data/db/migrate/20140926102943_create_arguments.rb +20 -0
  106. data/lib/concerns/controller/base_ranking_items_controller.rb +10 -0
  107. data/lib/concerns/model/base_ranking_item.rb +29 -0
  108. data/lib/concerns/model/user/ranking.rb +48 -0
  109. data/lib/tasks/voluntary_ranking_tasks.rake +4 -0
  110. data/lib/voluntary_ranking.rb +12 -0
  111. data/lib/voluntary_ranking/ability.rb +11 -0
  112. data/lib/voluntary_ranking/engine.rb +16 -0
  113. data/lib/voluntary_ranking/version.rb +3 -0
  114. metadata +436 -0
@@ -0,0 +1,29 @@
1
+ .tt-dropdown-menu, .gist
2
+ text-align: left
3
+
4
+ .tt-query
5
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset
6
+
7
+ .tt-hint
8
+ color: #999
9
+
10
+ .tt-dropdown-menu
11
+ background-color: #fff
12
+ border: 1px solid rgba(0, 0, 0, 0.2)
13
+ border-radius: 8px
14
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
15
+ margin-top: 12px
16
+ padding: 8px 0
17
+ width: 422px
18
+
19
+ .tt-suggestion
20
+ font-size: 18px
21
+ line-height: 24px
22
+ padding: 3px 20px
23
+
24
+ .tt-suggestion.tt-cursor
25
+ background-color: #0097cf
26
+ color: #fff
27
+
28
+ .tt-suggestion p
29
+ margin: 0
@@ -0,0 +1,12 @@
1
+ class Api::V1::ArgumentTopicsController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def autocomplete
7
+ render json: (
8
+ ArgumentTopic.order(:name).where("name LIKE ?", "%#{params[:term]}%").
9
+ map{|t| { id: t.id, value: t.name }}
10
+ ), root: false
11
+ end
12
+ end
@@ -0,0 +1,32 @@
1
+ class Api::V1::ArgumentsController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def index
7
+ options = {}
8
+
9
+ arguments = Argument
10
+ arguments = Argument.where(thing_id: params[:thing_id]) if params[:thing_id].present?
11
+ options[:json] = arguments.paginate(page: params[:page], per_page: 10)
12
+
13
+ options[:meta] = {
14
+ pagination: {
15
+ total_pages: options[:json].total_pages, current_page: options[:json].current_page,
16
+ previous_page: options[:json].previous_page, next_page: options[:json].next_page
17
+ }
18
+ }
19
+
20
+ respond_with do |format|
21
+ format.json { render options }
22
+ end
23
+ end
24
+
25
+ def create
26
+ raise CanCan::AccessDenied if current_user.blank?
27
+
28
+ respond_to do |format|
29
+ format.json { render json: Argument.create_with_topic(params[:argument]) }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,43 @@
1
+ class Api::V1::RankingItemsController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+ include Concerns::Controller::BaseRankingItemsController
4
+
5
+ respond_to :json
6
+
7
+ def index
8
+ options = {}
9
+
10
+ if ranking.present?
11
+ options[:json] = ranking.items.order('position').includes(:thing).paginate(page: params[:page], per_page: 10)
12
+
13
+ options[:meta] = {
14
+ pagination: {
15
+ total_pages: options[:json].total_pages, current_page: options[:json].current_page,
16
+ previous_page: options[:json].previous_page, next_page: options[:json].next_page
17
+ }
18
+ }
19
+ else
20
+ options[:json] = []
21
+ options[:meta] = { pagination: { total_pages: 0, current_page: 0, previous_page: 0, next_page: 0 } }
22
+ end
23
+
24
+ respond_with do |format|
25
+ format.json { render options }
26
+ end
27
+ end
28
+
29
+ def show
30
+ ranking = Ranking.where(
31
+ '(LOWER(adjective) = :adjective OR LOWER(negative_adjective) = :adjective) AND LOWER(topic) = :topic AND LOWER(scope) = :scope',
32
+ adjective: params[:adjective].downcase, topic: params[:topic].downcase, scope: params[:scope].downcase
33
+ ).first
34
+ thing = Thing.where('LOWER(name) = ?', params[:thing_name].downcase).first
35
+ ranking_item = RankingItem.where(ranking_id: ranking.try(:id), thing_id: thing.try(:id)).first
36
+
37
+ raise ActiveRecord::RecordNotFound if ranking_item.blank?
38
+
39
+ respond_with do |format|
40
+ format.json { render json: ranking_item }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ class Api::V1::RankingsController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def index
7
+ options = {}
8
+
9
+ rankings = Ranking
10
+ rankings = Ranking.for_user(params[:user_name]) if params[:user_name].present?
11
+ rankings = Ranking.for_thing(params[:thing_id]) if params[:thing_id].present?
12
+ options[:json] = rankings.paginate page: params[:page], per_page: 1, count: { group: 'rankings.id' }
13
+
14
+ options[:meta] = {
15
+ pagination: {
16
+ total_pages: options[:json].total_pages, current_page: options[:json].current_page,
17
+ previous_page: options[:json].previous_page, next_page: options[:json].next_page
18
+ }
19
+ }
20
+
21
+ respond_with do |format|
22
+ format.json { render options }
23
+ end
24
+ end
25
+
26
+ def autocomplete_attribute
27
+ render json: Ranking.autocomplete_attribute(params[:attribute], params[:term]), root: false
28
+ end
29
+ end
@@ -0,0 +1,40 @@
1
+ class Api::V1::Things::ArgumentsController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def comparison
7
+ options = {}
8
+
9
+ arguments = Argument.compare_two_things(params[:side], params[:left_thing_name], params[:right_thing_name]).
10
+ paginate(page: params[:page], per_page: 10)
11
+
12
+ options[:json] = arguments.map do |argument_comparison|
13
+ hash = {
14
+ left: { id: argument_comparison.id, value: argument_comparison.value },
15
+ right: { id: argument_comparison.right_id, value: argument_comparison.right_value },
16
+ topic: { id: argument_comparison.topic_id, name: argument_comparison.topic_name }
17
+ }
18
+
19
+ if params[:side] == 'right'
20
+ left = hash[:left].clone
21
+ right = hash[:right].clone
22
+ hash[:left] = right
23
+ hash[:right] = left
24
+ end
25
+
26
+ hash
27
+ end
28
+
29
+ options[:meta] = {
30
+ pagination: {
31
+ total_pages: arguments.total_pages, current_page: arguments.current_page,
32
+ previous_page: arguments.previous_page, next_page: arguments.next_page
33
+ }
34
+ }
35
+
36
+ respond_with do |format|
37
+ format.json { render options }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ class Api::V1::ThingsController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def show
7
+ @thing = Thing.where('LOWER(name) = ?', params[:id].downcase).first
8
+
9
+ raise ActiveRecord::RecordNotFound if @thing.blank?
10
+
11
+ respond_with do |format|
12
+ format.json { render json: @thing, root: true }
13
+ end
14
+ end
15
+
16
+ def autocomplete
17
+ render json: (
18
+ Thing.order(:name).where("name LIKE ?", "%#{params[:term]}%").
19
+ map{|t| { id: t.id, value: t.name }}
20
+ ), root: false
21
+ end
22
+
23
+ def suggest
24
+ render json: Thing.suggest(params[:term]), root: false
25
+ end
26
+ end
@@ -0,0 +1,94 @@
1
+ class Api::V1::UserRankingItemsController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+ include Concerns::Controller::BaseRankingItemsController
4
+
5
+ respond_to :json
6
+
7
+ def index
8
+ options = {}
9
+
10
+ if ranking.present?
11
+ options[:json] = if params[:user_id].present? || params[:user_name].present?
12
+ user.ranking_items
13
+ else
14
+ UserRankingItem
15
+ end
16
+
17
+ if params[:thing_name].present?
18
+ options[:json] = options[:json].where(
19
+ thing_id: Thing.where('LOWER(name) = ?', params[:thing_name].downcase).first.id
20
+ )
21
+ end
22
+
23
+ options[:json] = options[:json].order('position').where(ranking_id: ranking.id).includes(:thing)
24
+ options[:json] = options[:json].paginate(page: params[:page], per_page: 10)
25
+
26
+ options[:meta] = {
27
+ pagination: {
28
+ total_pages: options[:json].total_pages, current_page: options[:json].current_page,
29
+ previous_page: options[:json].previous_page, next_page: options[:json].next_page
30
+ }
31
+ }
32
+ else
33
+ options[:json] = []
34
+ options[:meta] = { pagination: { total_pages: 0, current_page: 0, previous_page: 0, next_page: 0 } }
35
+ end
36
+
37
+ respond_with do |format|
38
+ format.json { render options }
39
+ end
40
+ end
41
+
42
+ def create
43
+ raise CanCan::AccessDenied if current_user.blank?
44
+
45
+ respond_to do |format|
46
+ format.json { render json: current_user.add_ranking_item(params[:user_ranking_item]) }
47
+ end
48
+ end
49
+
50
+ def update
51
+ user_ranking_item = current_user.ranking_items.find(params[:id])
52
+ user_ranking_item.update_stars params[:user_ranking_item][:stars]
53
+ respond_with user_ranking_item
54
+ end
55
+
56
+ def move
57
+ user_ranking_item = UserRankingItem.find(params[:id])
58
+
59
+ raise CanCan::AccessDenied unless can? :update, user_ranking_item
60
+
61
+ user_ranking_item.set_position(params[:position].to_i)
62
+ respond_with user_ranking_item
63
+ end
64
+
65
+ def move_to_page
66
+ user_ranking_item = UserRankingItem.find(params[:id])
67
+
68
+ raise CanCan::AccessDenied unless can? :update, user_ranking_item
69
+
70
+ user_ranking_item.move_to_top_of_page(params[:page])
71
+
72
+ respond_to do |format|
73
+ format.json { render json: user_ranking_item }
74
+ end
75
+ end
76
+
77
+ def destroy
78
+ current_user.ranking_items.find(params[:id]).destroy!
79
+
80
+ render nothing: true
81
+ end
82
+
83
+ private
84
+
85
+ def user
86
+ if @user
87
+ @user
88
+ elsif params[:user_id].present?
89
+ @user = User.find(params[:user_id])
90
+ elsif params[:user_name].present?
91
+ @user = User.where('LOWER(name) = ?', params[:user_name].downcase).first
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,9 @@
1
+ class Api::V1::UsersController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def show
7
+ respond_with User.find(params[:id])
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ class Product::RankingController < Voluntary::EmberJs::ApplicationController
2
+ layout Proc.new { |controller| controller.request.xhr? || request.format.try('json?') ? false : 'voluntary/ember_js' }
3
+
4
+ def index
5
+ end
6
+
7
+ protected
8
+
9
+ def voluntary_ember_js_stylesheets
10
+ ['voluntary_ranking/application']
11
+ end
12
+
13
+ def voluntary_ember_js_javascripts
14
+ ['voluntary_ranking/application']
15
+ end
16
+ end
@@ -0,0 +1,48 @@
1
+ class Argument < ActiveRecord::Base
2
+ belongs_to :topic, class_name: 'ArgumentTopic'
3
+ belongs_to :thing
4
+
5
+ scope :compare_two_things, ->(side, left_thing_name, right_thing_name) do
6
+ left_thing_name, right_thing_name = right_thing_name, left_thing_name if side == 'right'
7
+
8
+ left_thing = Thing.where('LOWER(name) = ?', left_thing_name.downcase).first
9
+ right_thing = Thing.where('LOWER(name) = ?', right_thing_name.downcase).first
10
+
11
+ scope = joins(:topic).select('arguments.id, arguments.value, arguments.topic_id, argument_topics.name AS topic_name, arguments2.id AS right_id, arguments2.value AS right_value').
12
+ joins("#{side == 'both' ? 'INNER' : 'LEFT'} JOIN arguments arguments2 ON arguments2.thing_id = #{sanitize(right_thing.id)} AND arguments2.topic_id = arguments.topic_id")
13
+ scope = scope.where('arguments2.id IS NULL') unless side == 'both'
14
+ scope.where('arguments.thing_id = ?', left_thing.id)
15
+ end
16
+
17
+ validates :topic_id, presence: true
18
+ validates :thing_id, presence: true, uniqueness: { scope: :topic_id }
19
+ validates :value, presence: true
20
+
21
+ attr_accessible :topic_id, :thing_id, :value
22
+
23
+ def self.create_with_topic(attributes)
24
+ topic = ArgumentTopic.where('LOWER(name) = ?', attributes[:topic_name].to_s.strip.downcase).first
25
+
26
+ unless topic
27
+ topic = ArgumentTopic.create(name: attributes[:topic_name].to_s.strip)
28
+ end
29
+
30
+ if topic.valid?
31
+ thing_id = if attributes[:thing_name].present?
32
+ Thing.where('LOWER(name) = ?', attributes[:thing_name].downcase).first.id
33
+ else
34
+ Thing.where(id: attributes[:thing_id]).first.try(:id)
35
+ end
36
+
37
+ argument = Argument.create(topic_id: topic.id, thing_id: thing_id, value: attributes[:value])
38
+
39
+ if argument.valid?
40
+ argument
41
+ else
42
+ { errors: argument.errors.to_hash }
43
+ end
44
+ else
45
+ { errors: { topic: topic.errors.to_hash } }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ class ArgumentTopic < ActiveRecord::Base
2
+ has_many :arguments
3
+
4
+ validates :name, presence: true, uniqueness: { case_sensitive: false }
5
+
6
+ attr_accessible :name, :text
7
+ end
@@ -0,0 +1,2 @@
1
+ class Product::Ranking < ::Product
2
+ end
@@ -0,0 +1,97 @@
1
+ class Ranking < ActiveRecord::Base
2
+ attr_accessible :adjective, :topic, :scope, :negative_adjective
3
+
4
+ has_many :items, class_name: 'RankingItem', dependent: :destroy
5
+ has_many :user_items, class_name: 'UserRankingItem', dependent: :destroy
6
+
7
+ scope :for_user, ->(user_name) do
8
+ all.select('DISTINCT(rankings.id), rankings.*').joins(:user_items).
9
+ where('user_ranking_items.user_id = ?', User.where('LOWER(name) = ?', user_name.downcase).first.id)
10
+ end
11
+
12
+ scope :for_thing, ->(thing_id) do
13
+ all.select('DISTINCT(rankings.id), rankings.*').joins(:items).where('ranking_items.thing_id = ?', thing_id)
14
+ end
15
+
16
+ validates :adjective, presence: true
17
+ validates :topic, presence: true, uniqueness: { scope: [:adjective, :scope], case_sensitive: false }
18
+ validates :scope, presence: true
19
+ validate :one_ranking_per_topic_scope_and_one_of_the_adjectives
20
+
21
+ #pusherable "#{Rails.env}_channel"
22
+
23
+ def self.find_by_params(params)
24
+ scope = if params[:negative_adjective].present?
25
+ where(
26
+ 'LOWER(adjective) = ? AND LOWER(negative_adjective) = ?',
27
+ params[:adjective].downcase, params[:negative_adjective].downcase
28
+ )
29
+ else
30
+ where(
31
+ '(LOWER(adjective) = :adjective OR LOWER(negative_adjective) = :adjective)',
32
+ adjective: params[:adjective].downcase
33
+ )
34
+ end
35
+
36
+ scope.where(
37
+ 'LOWER(topic) = ? AND LOWER(scope) = ?', params[:topic].downcase, params[:scope].downcase
38
+ ).first
39
+ end
40
+
41
+ def self.find_or_create_by_params(params)
42
+ attributes = (params[:user_ranking_item] || params[:ranking_item] || params).clone
43
+ attributes.symbolize_keys! unless params.is_a?(ActiveSupport::HashWithIndifferentAccess)
44
+
45
+ if attributes[:ranking_id].present? then Ranking.find(attributes[:ranking_id])
46
+ elsif attributes[:adjective].present?
47
+ rankings = Ranking
48
+ ranking = Ranking.new
49
+
50
+ attributes.each do |param, value|
51
+ if ranking.respond_to?(param) && value.present?
52
+ rankings = rankings.where("LOWER(#{param}) = ?", value.downcase)
53
+ else
54
+ attributes.delete(param)
55
+ end
56
+ end
57
+
58
+ rankings.first || Ranking.create(attributes)
59
+ end
60
+ end
61
+
62
+ def self.autocomplete_attribute(attribute, term)
63
+ unless ['adjective', 'negative_adjective', 'topic', 'scope'].include? attribute
64
+ raise ActiveRecord::RecordNotFound
65
+ end
66
+
67
+ Ranking.select("DISTINCT(#{attribute})").order(attribute).limit(10).
68
+ where("#{attribute} LIKE ?", "%#{term.strip}%").map(&attribute.to_sym).map{|v| { value: v }}
69
+ end
70
+
71
+ private
72
+
73
+ def one_ranking_per_topic_scope_and_one_of_the_adjectives
74
+ if Ranking.where(
75
+ '(' +
76
+ 'LOWER(adjective) = :adjective OR LOWER(negative_adjective) = :adjective OR ' +
77
+ 'LOWER(adjective) = :negative_adjective OR LOWER(negative_adjective) = :negative_adjective' +
78
+ ') AND ' +
79
+ 'LOWER(topic) = :topic AND LOWER(scope) = :scope',
80
+ adjective: adjective.downcase, negative_adjective: negative_adjective.downcase,
81
+ topic: topic.downcase, scope: scope.downcase
82
+ ).any?
83
+ errors[:base] << I18n.t(
84
+ 'activerecord.errors.models.ranking.attributes.base.' +
85
+ 'one_ranking_per_topic_scope_and_one_of_the_adjectives'
86
+ )
87
+ end
88
+ end
89
+
90
+ def special_characters_excluded
91
+ if adjective.match(/\//) || negative_adjective.match(/\//) || topic.match(/\//) || scope.match(/\//)
92
+ errors[:name] << I18n.t(
93
+ 'activerecord.errors.models.ranking.attributes.name.unwanted_special_characters_included'
94
+ )
95
+ end
96
+ end
97
+ end