The merit ruby gem is not adding the points to the user with the "user.passion.present" added. It works without it. I set everything up with working with Devise and Merit gems. Everything seems to work except this.
module Merit
class PointRules
include Merit::PointRulesMethods
def initialize
score 50, :on => 'user/registrations#create', model_name: 'User'
score 10, :on => 'user/registrations#update', model_name: 'User' do |user|
user.passion.present?
end
#
# score 15, :on => 'reviews#create', :to => [:reviewer, :reviewed]
#
# score 20, :on => [
# 'comments#create',
# 'photos#create'
# ]
score 20, on: 'lyrics#create', to: :user, description: 'Plus 20 points'
score (-20), on: 'lyrics#destroy', to: :user
end
end
end
Did you add the instance variable to the update overridden action?
See wiki page: https://github.com/tute/merit/wiki/How-to-grant-badges-on-user-registration-using-Devise.
Related
Why won't my module load properly when I include it in my presenter class?
My class methods and module methods are not available when loading from rails. The module works when loading out of rails in a single file.
app/presenters/body_parts/method_wrapper.rb
module BodyParts
def self.included(klass)
klass.extend ClassMethods # => Car
end # => :included
module ClassMethods
def set_wheels(*args)
x, *wheel_args = args # => [3], [3]
puts "Wheels class method called with: #{x.to_s}" # => nil, nil
#wheels |= x # => true, true
end # => :set_wheels
class MethodWrapper
attr_reader :klass # => nil
def initialize(klass)
#klass = klass
end # => :initialize
def wrap(method_name)
puts "Wrapping a method"
wrapper_callback(result)
end # => :wrap
end # => :wrap
end # => :wrap
private # => BodyParts
def wrapper_callback(result)
"Wrapped a #{result} in the call back"
end # => :wrapper_callback
end # => :wrapper_callback
app/presenters/car_presenter.rb
class CarPresenter
include BodyParts # => Car
set_wheels 3 # => true
def brand
'Car Brand' # => "Car Brand"
end # => :brand
set_wheels 3 # => true
def title # policy set to 2 for title methods because of the above
'Car Title'
end # => :title
end # => :title
car_presenter = CarPresenter.new # => #<CarPresenter:0x00fe4ed9300>
car_presenter.brand # => "Car Brand"
# >> Wheels class method called with: 3
# >> Wheels class method called with: 3
Binding.pry from CarsPresenter in Rails
[1] pry(CarPresenter)> set_wheels 3
NameError: undefined local variable or method `set_wheels' for CarPresenter:Class
from (pry):12:in `<class:CarPresenter>'
[2] pry(CarPresenter)> BodyParts
=> BodyParts
[3] pry(CarPresenter)> self
=> CarPresenter
Due to the way const loading works in rails, a module BodyParts should be defined in the top level of presenters directory, i.e. in app/presenters/body_parts.rb.rb.
Rails expects app/presenters/body_parts/method_wrapper.rb to define const BodyParts::MethodWrapper,
Read mode in rails guides.
We're trying to set up rails routes with the parameters separated by more then just forward-slash symbols.
As an example:
someexample.com/SOME-ITEM-for-sale/SOME-PLACE
For the following path we'd like to extract SOME-ITEM and SOME-PLACE strings as parameters whilst identifying which controller to run it all against with the "-for-sale/" part.
I've been playing with variations on :constraints => {:item => /[^\/]+/} constructs but without any success. Am I looking in the right place? Thanks!
UPDATE
In the end I went with this solution:
get ':type/*place' => 'places#index', as: :place , :constraints => {:type => /[^\/]+-for-sale/}
And then recovered the full "SOME-ITEM-for-sale" sting for parsing in the controller using
params[:type]
Hope that helps someone!
friendly_id is what you want:
#Gemfile
gem 'friendly_id', '~> 5.1.0'
$ rails generate friendly_id
$ rails generate scaffold item name:string slug:string:uniq
$ rake db:migrate
#app/models/item.rb
class Item < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: [:slugged, :finders]
end
The above will give you a slug column, which FriendlyId will look up any requests you send to the app:
#config/routes.rb
resources :items, path: "" do
resources :places, path: "" #-> url.com/:item_id/:id
end
Although the params will still be id (unless you use the param option of resources, but FriendlyId will override both your routes and model to use the slug instead:
<%= link_to "Item Place", items_place_path(#item, #place) %> #-> url.com/item-name-information/place-name-information
Update
If you wanted to have a "dynamic" routing structure, you'll be able to use the following (this requires the history module of FriendlyId):
#config/routes.rb
#...
get '/:item_id/:place_id', to: SlugDispatcher.new(self), as: :item #-> this has to go at the bottom
#lib/slug_dispatcher.rb
class SlugDispatcher
#http://blog.arkency.com/2014/01/short-urls-for-every-route-in-your-rails-app/
##########################################
#Init
def initialize(router)
#router = router
end
#Env
def call(env)
id = env["action_dispatch.request.path_parameters"][:item_id]
slug = Slug.find_by slug: id
if slug
strategy(slug).call(#router, env)
else
raise ActiveRecord::RecordNotFound
end
end
##########################################
private
#Strategy
def strategy(url)
Render.new(url)
end
####################
#Render
class Render
def initialize(url)
#url = url
end
def call(router, env)
item = #url.sluggable_type.constantize.find #url.sluggable_id
controller = (#url.sluggable_type.downcase.pluralize + "_controller").classify.constantize
action = "show"
controller.action(action).call(env)
end
end
####################
end
This won't work out the box (we haven't adapted it for nested routes yet), but will provide you the ability to route to the appropriate controllers.
In the end we went with this solution:
get ':type/*place' => 'places#index', as: :place , :constraints => {:type => /[^\/]+-for-sale/}
The router command only gets activated if the :type parameter contains "-for-sale" in the string
And then we recovered the full "SOME-ITEM-for-sale" sting for parsing in the controller using
params[:type]
Hope that helps someone!
My objective is to dynamically load a set of methods to an ActiveRecord model instance based on an attribute that's set:
class Book < ActiveRecord::Base
after_initialize do |cp|
self.class.include "#{cp.subject}".constantize
end
end
I then have the following concerns:
module Ruby
extend ActiveSupport::Concern
def get_framework
'rails'
end
end
module Python
extend ActiveSupport::Concern
def get_framework
'django'
end
end
Then, when I run these separately, I get the correct framework string:
python_book = Book.create(:subject => 'python', :id => 1)
python_book.get_framework -> 'django'
ruby_book = Book.create(:subject => 'ruby', :id => 2)
ruby_book.get_framework -> 'rails'
My problem is that when I have both of the books returned in a query, the Concern is included is the last in the result set and is not picking up the correct Concern methods.
Books.all.order(:id => 'asc').collect do |book|
puts book.get_framework
end
# Result
['rails', 'rails']
I am assuming that this is because the 'include' is happening at the class level and not the instance level. Would love some help as to how to clean this up and make this work.
Use .extend
to add instance methods to a instances of Book instead.
Extends in action:
module Greeter
def say_hello
"Hello"
end
end
irb(main):008:0> a = Object.new
=> #<Object:0x00000101e01c38>
irb(main):009:0> a.extend(Greeter)
=> #<Object:0x00000101e01c38>
irb(main):010:0> a.say_hello
=> "Hello"
irb(main):011:0> Object.new.say_hello
NoMethodError: undefined method `say_hello' for #<Object:0x00000101e196d0>
class Book < ActiveRecord::Base
after_initialize do |cp|
self.extend subject.constantize
end
end
The goal is to give a user points when his comment gets an upvote. Now it just gives points when the comment is created(5 points) and doesn't count upvotes.
I've looked at this answer and according to it my code is correct. I'm using acts_as_votable gem for upvotes/downvotes.
gemfile
gem 'merit', '~> 2.1.1'
comments_controller
def upvote
#comment.liked_by current_user
render "update_likes"
end
point_rules
module Merit
class PointRules
include Merit::PointRulesMethods
def initialize
score 5, :on => ['comments#create'], :to => [:user], category: 'gold_points'
score 2, :on => ['comments#upvote'], :to => [:user], category: 'gold_points'
end
end
end
user model
class User < ActiveRecord::Base
has_merit
display points
<%= #user.points(category: 'gold_points') %>
I found the answer:
change
render "update_likes"
to
render :nothing => true
I need a checkout process devoid of a delivery and payment step
(working on a store which accept cash on delivery so I need only the
address step.)
I am using Spree 0.10.2
Things I have tried:
In the site_extension.rb added the following state machine
Checkout.state_machines[:state] = StateMachine::Machine.new(Checkout, :initial => 'address') do
after_transition :to => 'complete', :do => :complete_order
before_transition :to => 'complete', :do => :process_payment
event :next do
transition :to => 'complete', :from => 'address'
end
end
The unwanted steps are removed (at least visually) but when I submit
the address it throws up the following error.
IndexError in
CheckoutsController#update
"payment" is an invalid name
Looking at the trace and couple of similar errors later, I decide to
blindly override two methods from checkouts_controller.rb in
site_extension.rb to do nothing (since they deal with payment I
presume)
def clear_payments_if_in_payment_state
end
def object_params
end
Doing this throws validation errors on all the fields of delivery and
billing address.
I vaguely have a notion that I need to override a couple of methods
from checkouts_controller.rb. If this notion is right then what are
those methods.
You need to :
1) Remove the paymenttransition and delivery state transition step.
2) Also overriding the payment_required method .
3) These steps need to be in order_decorator.rb under app/models/spree directory.
checkout_flow do
go_to_state :address
# go_to_state :payment
go_to_state :complete
remove_transition :from => :delivery, :to => :confirm
remove_transition :from => :delivery, :to => :confirm
remove_transition :from => :payment, :to => :confirm
end
#Spree::Order.state_machine.before_transition :to => :payment, :do => :set_order
def set_order
self.create_proposed_shipments
end
def require_email
return false
end
def payment_required?
false
end
I have tested this on spree 2-0-stable with rails 3.2.14.
Sorry, I can't really help you: Customizing the checkout process with Spree 0.10.2 is kind of a nightmare.
But I would recommend to switch to a more recent version of Spree, like the 1.3-stable.
If you switched to that one, it would be as easy as creating an order_decorator.rb file in your_app_folder/app/models/spree with the following code:
Spree::Order.class_eval do
remove_checkout_step :delivery
remove_checkout_step :payment
end