Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Reviews #180

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ env:
gemfile:
- gemfiles/spree_3_1.gemfile
- gemfiles/spree_3_2.gemfile
- gemfiles/spree_4_0.gemfile
- gemfiles/spree_master.gemfile

script:
Expand All @@ -19,8 +20,10 @@ script:
rvm:
- 2.3.1
- 2.2.7
- 2.3.8

addons:
postgresql: 9.4
apt:
packages:
- mysql-server-5.6
Expand Down
6 changes: 6 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ appraise 'spree-3-3' do
gem 'rails-controller-testing'
end

appraise 'spree-4-0' do
gem 'spree', '~> 4.0.0'
gem 'spree_auth_devise', '~> 4.0'
gem 'rails-controller-testing'
end

appraise 'spree-master' do
gem 'spree', github: 'spree/spree', branch: 'master'
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: 'master'
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Straightforward review/rating functionality.

## Installation

#### Spree >= 3.1
#### Spree >= 4.0

```ruby
gem 'spree_reviews', github: 'spree-contrib/spree_reviews'
Expand Down
1 change: 0 additions & 1 deletion app/assets/javascripts/spree/frontend/spree_reviews.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//= require jquery.rating
//= require spree/frontend
//= require spree/frontend/spree_auth

// Navigating to a page with ratings via TurboLinks shows the radio buttons
$(document).on('page:load', function () {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Spree
module Api
module V2
module Storefront
module Account
class UserReviewsController < ::Spree::Api::V2::BaseController
before_action :require_spree_current_user

# GET /api/v2/storefront/account/reviews
def index
render_serialized_payload { serialize_collection(resource) }
end

private

def resource
resource_finder.user_reviews(spree_current_user.id).most_recent_first
end

def collection_serializer
Spree::V2::Storefront::ReviewSerializer
end

def serialize_collection(collection)
collection_serializer.new(
collection,
include: resource_includes,
fields: sparse_fields
).serializable_hash
end

def resource_finder
Spree::Review
end
end
end
end
end
end
end
97 changes: 97 additions & 0 deletions app/controllers/spree/api/v2/storefront/reviews_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
module Spree
module Api
module V2
module Storefront
class ReviewsController < ::Spree::Api::V2::BaseController
include Spree::Api::V2::CollectionOptionsHelpers

before_action :load_product, only: [:index, :create]

def index
render_serialized_payload {serialize_collection(paginated_collection)}
end

def show
render_serialized_payload {serialize_resource(resource)}
end

def create
# TODO move to service
# result = create_service.call(user: spree_current_user, review_params: review_params, product: @product, ip_address: request.remote_ip)

params[:review][:rating].sub!(/\s*[^0-9]*\z/, '') unless params[:review][:rating].blank?

@review = Spree::Review.new(review_params)
@review.product = @product
@review.user = spree_current_user if spree_user_signed_in?
@review.ip_address = request.remote_ip
@review.locale = I18n.locale.to_s if Spree::Reviews::Config[:track_locale]

# TODO: @prakash fix permission
# authorize! :create, @review

render_result(@review)
end

private

def create_service
Spree::Api::Dependencies.storefront_account_create_address_service.constantize
end

def scope
Spree::Review
end

def resource
scope.find(params[:id])
end

def collection_serializer
Spree::V2::Storefront::ReviewSerializer
end

def resource_serializer
Spree::V2::Storefront::ReviewSerializer
end

def paginated_collection
collection_paginator.new(collection, params).call
end

def collection
Spree::Review.approved.where(product: @product)
end

def load_product
@product = Spree::Product.friendly.find(params[:product_id])
end

def permitted_review_attributes
[:rating, :title, :review, :name, :show_identifier]
end

def review_params
params.require(:review).permit(permitted_review_attributes)
end

def render_result(review)
if review.save
render_serialized_payload {serialize_resource(review)}
else
# TODO handle error from service
render_error_payload(review.errors)
end
# if result.success?
# render_serialized_payload { serialize_resource(result.value) }
# else
# render_error_payload(result.error)
# end
end


end
end
end
end
end
8 changes: 6 additions & 2 deletions app/controllers/spree/products_controller_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
Spree::ProductsController.class_eval do
helper Spree::ReviewsHelper
module Spree::ProductsControllerDecorator
def self.prepended(base)
base.helper Spree::ReviewsHelper
end

reviews_fields = [:avg_rating, :reviews_count]
reviews_fields.each { |attrib| Spree::PermittedAttributes.product_attributes << attrib }
Expand All @@ -8,3 +10,5 @@
reviews_fields.each { |attrib| class_variable_set(:@@product_attributes, class_variable_get(:@@product_attributes).push(attrib)) }
end
end

::Spree::ProductsController.prepend(Spree::ProductsControllerDecorator)
31 changes: 19 additions & 12 deletions app/models/spree/product_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
# Add access to reviews/ratings to the product model
Spree::Product.class_eval do
has_many :reviews
module Spree
module ProductDecorator

def stars
avg_rating.try(:round) || 0
end
def self.prepended(base)
base.has_many :reviews
end

def recalculate_rating
self[:reviews_count] = reviews.reload.approved.count
if reviews_count > 0
self[:avg_rating] = reviews.approved.sum(:rating).to_f / reviews_count
else
self[:avg_rating] = 0
def stars
avg_rating.try(:round) || 0
end

def recalculate_rating
self[:reviews_count] = reviews.reload.approved.count
if reviews_count > 0
self[:avg_rating] = reviews.approved.sum(:rating).to_f / reviews_count
else
self[:avg_rating] = 0
end
save
end
save
end
end

Spree::Product.prepend Spree::ProductDecorator
3 changes: 2 additions & 1 deletion app/models/spree/review.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Spree::Review < ActiveRecord::Base
belongs_to :product, touch: true
belongs_to :user, class_name: Spree.user_class.to_s
belongs_to :user, class_name: Spree.user_class.to_s, optional: true
has_many :feedback_reviews

after_save :recalculate_product_rating, if: :approved?
Expand All @@ -23,6 +23,7 @@ class Spree::Review < ActiveRecord::Base
scope :approved, -> { where(approved: true) }
scope :not_approved, -> { where(approved: false) }
scope :default_approval_filter, -> { Spree::Reviews::Config[:include_unapproved_reviews] ? all : approved }
scope :user_reviews, ->(user_id) { where('spree_reviews.user_id = ?', user_id) }

def feedback_stars
return 0 if feedback_reviews.size <= 0
Expand Down
14 changes: 14 additions & 0 deletions app/serializers/spree/v2/storefront/review_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Spree
module V2
module Storefront
class ReviewSerializer < BaseSerializer
set_type :review

attributes :title, :review, :rating

has_one :user
has_one :product
end
end
end
end
14 changes: 14 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,18 @@
end
end
post '/reviews/:review_id/feedback(.:format)' => 'feedback_reviews#create', as: :feedback_reviews

namespace :api, defaults: { format: 'json' } do
namespace :v2 do
namespace :storefront do
resources :products, only: [] do
resources :reviews, only: [:index, :create]
end

namespace :account do
resources :reviews, controller: :user_reviews, only: %i[index]
end
end
end
end
end
9 changes: 9 additions & 0 deletions gemfiles/spree_4_0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "spree", "~> 4.0.0"
gem "spree_auth_devise", "~> 4.0"
gem "rails-controller-testing"

gemspec path: "../"
16 changes: 16 additions & 0 deletions spec/models/review_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@
expect(Spree::Review.default_approval_filter.to_a).to match_array expected
end
end

context 'user_reviews' do
let!(:user_1) { create(:user, email: '[email protected]') }
let!(:user_2) { create(:user, email: '[email protected]') }

let!(:review_1) { create(:review, created_at: 10.days.ago, user: user_1) }
let!(:review_2) { create(:review, created_at: 2.days.ago, user: user_2) }

it 'properly runs user_reviews queries' do
expect(described_class.user_reviews(user_1).to_a).to eq([review_1])
end

it 'does not show other users reviews' do
expect(described_class.user_reviews(user_2).to_a).to eq([review_2])
end
end
end

context '.recalculate_product_rating' do
Expand Down
2 changes: 1 addition & 1 deletion spree_reviews.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Gem::Specification.new do |s|
s.require_path = 'lib'
s.requirements << 'none'

spree_version = '>= 3.1.0', '< 4.0'
spree_version = '>= 3.1.0', '< 5.0'
s.add_runtime_dependency 'spree_core', spree_version
s.add_runtime_dependency 'spree_auth_devise', spree_version
s.add_runtime_dependency 'spree_extension'
Expand Down