amatsuda / active_decorator Goto Github PK
View Code? Open in Web Editor NEWORM agnostic truly Object-Oriented view helper for Rails 4, 5, 6, and 7
License: MIT License
ORM agnostic truly Object-Oriented view helper for Rails 4, 5, 6, and 7
License: MIT License
Unless I manually include my decorators into my models, my tests (RSpec and Turnip) that utilize decorator methods fail. I'd be happy to work on this and submit a pull request if you want to give your input and point me in the right direction. Thanks.
If automatically mixes decorator module into corresponding model only when:
How could I to test my decorator's methods with RSpec? Check it out https://gist.github.com/glaucocustodio/81e2d036c67b893c1e6a
Thank you.
It's okay to use decorator methods in actionview,
but just like the following case, if I use decorator method in other decorator, it will be confronted with error.
it will be wonderful if it's possible to use decorator methods in decorator. that's the feature that needed in my situation.
Any ideas please.
module ClassADecorator
def mtd_a
"this is mtd a"
end
end
module ClassBDecorator
def mtd_b
# error, undefined method `mtd_a' for #<ClassA>
ClassA.new.mtd_a
end
end
Currently the repo description reads "ORM agnostic truly Object-Oriented view helper for Rails 3 and Rails 4", but should now read "ORM agnostic truly Object-Oriented view helper for Rails 3, 4, and 5".
rails g decorator Foo::Bar
creates */decorators/bar_decorator*
, but I expected */decorators/foo/bar_decorator*
.
% rails g decorator Foo::Bar
create app/decorators/bar_decorator.rb
invoke rspec
create spec/decorators/bar_decorator_spec.rb
"since decorators are considered as sort of helpers, you can also call any ActionView's helper methods such as content_tag or link_to"
This does not work for me, I must to include manually required modules:
include ActionView::Helpers::TagHelper
include ActionView::Helpers::FormHelper
etc
I am not sure but I found myself pretty often I need an application url_helpers are included too, in order to use __path or __url helpers in link_to method for example.
I've created a helper module and include it where needed, but I think it would be nice to have it included automatically.
module DecoratorUrlHelpers
include ActionView::Helpers::UrlHelper
def url_helpers
MyApplication::Application.routes.url_helpers
end
end
and then in my Decorator I do
module UserDecorator
include DecoratorUrlHelpers
def some_link
link_to "Darth Vader" death_star_path
end
end
On writing my UserDecorator
, I find it overlap a lot. Just decorate the datetime
but I have to repeat writing decorator a lot.
# frozen_string_literal: true
module UserDecorator
def created_at_datetime
created_at&.strftime '%Y/%m/%m %H:%M:%S'
end
def confirmed_at_datetime
confirmed_at&.strftime '%Y/%m/%m %H:%M:%S'
end
def locked_at_datetime
locked_at&.strftime '%Y/%m/%m %H:%M:%S'
end
def current_sign_in_at_datetime
current_sign_in_at&.strftime '%Y/%m/%m %H:%M:%S'
end
def last_sign_in_at_datetime
last_sign_in_at&.strftime '%Y/%m/%m %H:%M:%S'
end
end
And guess what, on my AdminDecorator
I have the exact same fields. Do I have to copy all of these again to AdminDecorator?
Any advice guys?
This is reproduced Rails application.
[email protected]:taki/active_decorator_view_context.git
It does not raise error.
「NameError: undefined local variable or method `view_context'」 is displayed.
This doesn't work with ActionController::API. I added an initializer with this code:
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
ActiveSupport.on_load(:action_controller) do
require 'active_decorator/monkey/abstract_controller/rendering'
ActionController::API.send :prepend, ActiveDecorator::Monkey::AbstractController::Rendering
require 'active_decorator/monkey/action_controller/base/rescue_from'
ActionController::API.send :prepend, ActiveDecorator::Monkey::ActionController::Base
ActionController::API.send :include, ActiveDecorator::ViewContext::Filter
end
Do you think this is enough to support AC::API? I can add it to the project.
NameError: uninitialized constant ActionView::AbstractRenderer
~/.rvm/gems/ruby-1.9.3-p0/gems/active_decorator-0.2.1/lib/active_decorator/monkey/action_view/partial_renderer.rb:2:in `<module:ActionView>'
~/.rvm/gems/ruby-1.9.3-p0/gems/active_decorator-0.2.1/lib/active_decorator/monkey/action_view/partial_renderer.rb:1:in `<top (required)>'
~/.rvm/gems/ruby-1.9.3-p0/gems/active_decorator-0.2.1/lib/active_decorator/railtie.rb:7:in `block (2 levels) in <class:Railtie>'
~/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.0.11/lib/active_support/lazy_load_hooks.rb:36:in `instance_eval'
~/.rvm/gems/ruby-1.9.3-p0/gems/activesupport-3.0.11/lib/active_support/lazy_load_hooks.rb:36:in `execute_hook'
Gemfile:
gem 'rails', '~> 3.0.7'
gem 'sqlite3'
gem 'haml-rails'
gem 'sass'
gem 'compass'
gem 'redcarpet', '< 2.0.0'
gem 'auto_html'
gem 'activeadmin'
gem 'validate_email'
gem 'date_validator'
gem 'paperclip', '~> 2.3.0'
gem 'friendly_id', '~> 3.3.1'
gem 'hpricot'
gem 'active_decorator'
group :development do
gem 'active_reload'
gem 'capistrano'
gem 'capistrano_colors', :require => false
end
What am I doing wrong?
Model:
class Promoter
class Role < ApplicationRecord
end
end
Decorator:
class Promoter
class RoleDecorator
def _permissions; end
end
end
Error:
NoMethodError:
undefined method `_permissions' for #<Promoter::Role id: nil, ...
I'm trying to decorate an API response object but it's not working...
class RegistrationsController < Devise::RegistrationsController
helper_method :orders
def orders
@orders ||= PreApproval.orders resource.subscription_code # returns an array of PagSeguro::SubscriptionPaymentOrder
end
end
# app/decorators/order_decorator.rb
module PagSeguro::SubscriptionPaymentOrderDecorator
def something
end
end
# on the view (triggers NoMethodError)
orders.first.something
Any ideas?
Hi guys, if I have something like that:
class User < ActiveRecord::Base; end
class Customer < User; end
If I do have a UserDecorator
but dont have a CustomerDecorator
, shouldn't active_decorator
load UserDecorator
if my object is a User
instance with type="Customer"
?
Is it similar to drapergem/draper#468?
Thanks.
when using with a jbuilder
partial i get:
:companies=>
[{:is_a?=>{},
:respond_to?=>"to_a_with_decorator",
:id=>1,
:name=>"Carter and Sons",
:logo_url=>"/media/W1siZiIsInNvbWUvdWlkL3BhdGgiXV0?sha=9fc68caa72d460cb"}],
:success=>true}
not sure why :is_a?=>{}
and :respond_to?=>"to_a_with_decorator"
get added. Thoughts?
When I have in decorator path/url helper it will fail
How can I add this when I test with rspec. Thank you
From the readme, it says:
ActiveDecorator::ViewContext.run_with ApplicationController.new.view_context do
## perform some heavy jobs here
end
However, what I did is the following
↪ rails runner 'ActiveDecorator::ViewContext.run_with(ApplicationController.new.view_context) { puts User.last.name_with_company }'
undefined method `name_with_company' for #<User:0x000000000b63ee70>
Did you mean? name_will_change!
but maually extend would work:
↪ rails runner 'u = User.last; u.extend UserDecorator; puts u.name_with_company'
Foo Bar
Am i missing sth?
Regards
First of all, thank you very much for this nice gem ! 👍
Like 99% Rails projets I'm using devise in order to manage users and I'd like to decorate the current_user
object from Devise and I'm wondering what would be the best way to do it?
As of now, based on this blog article and this issue I've added the following to my ApplicationController
:
class ApplicationController < ActionController::Base
# ...
def current_user
ActiveDecorator::Decorator.instance.decorate(super) unless super.nil?
end
end
This works just fine.
def show
c1 = ::ActiveDecorator::ViewContext.current
MyMailer.greeting.deliver_now
c2 = ::ActiveDecorator::ViewContext.current
puts c1 == c2 #=> false
end
Send an email, and current view context unexpectedly switches from the controller's one to the mailer's, a decorated instance in the following processes working with the latter.
I git-bisect-ed and found this behavior had been introduced by e5dbf4c.
I executed rails g scaffold Post title:string body:text
.
And add following code.
module PostDecorator
def sample
"sample"
end
end
<!DOCTYPE html>
<html>
<head>
<title>SampleApp</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
<%= Post.first.sample %>
</head>
<body>
<%= yield %>
</body>
</html>
I got following error.
$ ./bin/rake test
Running via Spring preloader in process 1153
Loaded suite rake
Started
..E
================================================================================
Error: test: should get edit(PostsControllerTest): ActionView::Template::Error: undefined method `sample' for #<Post:0x00000005550320>
/home/kenji/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/activemodel-4.2.5/lib/active_model/attribute_methods.rb:433:in `method_missing'
/home/kenji/Data/ruby/sample-app/app/views/layouts/application.html.erb:8:in `_app_views_layouts_application_html_erb__3560731179302627099_42502300'
/home/kenji/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/actionview-4.2.5/lib/action_view/template.rb:145:in `block in render'
/home/kenji/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/activesupport-4.2.5/lib/active_support/notifications.rb:164:in `block in instrument'
... too long backtrace
.
Finished in 1.080862742 seconds.
--------------------------------------------------------------------------------
8 tests, 9 assertions, 0 failures, 4 errors, 0 pendings, 0 omissions, 0 notifications
50% passed
--------------------------------------------------------------------------------
7.40 tests/s, 8.33 assertions/s
I want to use decorator methods in layout, but I couldn't.
I moved decorator methods to helper methods and use helper methods in layout.
Thanks.
How is this possible? I know super call the original method in decorator, but take a look at my problem.
I am trying to create a form in Rails with:
f.date_field :start_date
But since I decorated that field I do not get the edit form with right values:
module MyDecorator
def start_date
l super
end
end
With the recent update to Rails 6.1 using ApplicationController.renderer.render causes automatic locals variable decoration to fail
I attempted to update my Ruby version from 2.7.7 to 3.0.5, and now I am encountering the following error when running RSpec:
The error stack trace is as follows:
/home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/view_context.rb:20:in `view_context_stack': stack level too deep (SystemStackError)
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/view_context.rb:8:in `current'
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/helpers.rb:12:in `rescue in method_missing'
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/helpers.rb:6:in `method_missing'
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/helpers.rb:14:in `rescue in method_missing'
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/helpers.rb:6:in `method_missing'
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/helpers.rb:14:in `rescue in method_missing'
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/helpers.rb:6:in `method_missing'
from /home/circleci/repo/vendor/bundle/ruby/3.0.0/gems/active_decorator-1.4.0/lib/active_decorator/helpers.rb:14:in `rescue in method_missing'
... 9349 levels...
from /home/circleci/.rubygems/gems/bundler-2.4.10/lib/bundler/friendly_errors.rb:115:in `with_friendly_errors'
from /home/circleci/.rubygems/gems/bundler-2.4.10/exe/bundle:33:in `<top (required)>'
from /home/circleci/.rubygems/bin/bundle:25:in `load'
from /home/circleci/.rubygems/bin/bundle:25:in `<main>'
From reading the stack trace, it seems that:
current
method cannot be executed in lib/active_decorator/view_context.rb
lib/active_decorator/helpers.rb
is loopingI am unsure how to address this issue and would appreciate any guidance.
If anyone has any insights or suggestions, I would greatly appreciate your comments. Thank you in advance.
Hi @amatsuda ,
I'm using draper
and found your gem that looks cleaner on dependency. Would you provide a comparison between both?
Automatically decorate the object couldn't be bad? Since it is not always we need the decorator methods? And what do you think about to use the same method name on decorator?
ActiveDecorator generally does a nice job decorating active record associations, but there are gaps. For example:
author = ActiveDecorator::Decorator.instance.decorate(Author.first)
puts author.books.first.is_a?(ActiveDecorator::Decorated) # => true
puts author.books.order(:id).first.is_a?(ActiveDecorator::Decorated) # => false
Same for includes
. This is easy enough to workaround and I don't want to complicate the gem, but I figured I'd raise the issue so we can document the behavior and consider fixes.
Thanks for all your hard work on this gem!
Hi there, thanks for creating such a great project!
We noticed that a particular request in our Rails app was slow. Eventually we traced the problem to a decorator that was calling image_tag
. Each call results in a method_missing
through ActiveDecorator, which delegates to the view context. The overhead for each call is around 1ms, and we are calling image_tag 100 times, so the decorator was slowing down the page by 100ms.
Not sure about the proper fix. Can we mix in the helpers directly somehow, instead of relying on method_missing & view context? Should we call define_method
to add missing methods as they are detected? Should we expose view_context
and force decorators to call it directly?
For a quick demonstration, add poof!
inside the BookDecorator#cover_image
in test/fake_app/fake_app.rb#L83
and run the tests. Instead of a NameError
we get a SystemStackError
.
In my Rails 5 (v 5.0.0.1) app with the puma application server (v 3.6.2) and ruby 2.3.3 I get a fatal (exception reentered)
.
This is because in ActiveDecorator::Helpers#method_missing
when a NameError
occurs the method is tried on the original object and then the view context. An exception with the former acts as the original error but it is raised again while handling exception with the later. This means the original object exception is caused by the view context exception which is itself caused by the original object exception creating a loop of causes which end up trapped in ActiveSupport::Rescuable#rescue_with_handler
.
It looks like when you have a situation:
class Order < ActiveRecord::Base
has_one :coupon
end
class Coupon < ActiveRecord::Base
belongs_to :order
end
module CouponDecorator
def type_description
#some logic here
end
end
Now when in the view I call
<%= order.coupon.type_description %>
I've got NoMethod exception, but if I call in the another view
<%= coupon.type_description %>
it works fine.
The only one workaround I found for now is to create a method in Coupon model with the same name as decorator
def type_description
ActiveDecorator::Decorator.instance.decorate(self).type_description
end
and now it will work with the calls such as
<%= order.coupon.type_description %>
but it does not looks good to me, is there any better solution?
Here's the backtrace.
https://gist.github.com/rainerborene/b0906fbfd75ef6f028935ce73d576fa7
And here's the solution:
# frozen_string_literal: true
# A monkey-patch for Action Controller to pass the controller view_context over
# to `render` invocation in `rescue_from` block.
module ActiveDecorator
module Monkey
module ActionController
module Base
def rescue_with_handler(*)
ActiveDecorator::ViewContext.push(view_context) if defined? view_context
super
ensure
ActiveDecorator::ViewContext.pop
end
end
end
end
end
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.