How to use decorator in rails correctly? - ruby-on-rails

I'm newbie in using decorators and I need your help to understand how to use it right and what am I doing wrong.
book_decorator.rb
class BookDecorator < ApplicationDecorator
delegate_all
def in_users_list?(user)
if user.books.exists?
true
end
end
end
views/books/index.html.slim
- if book.in_users_list?(current_user)
- button_text = 'I've read this book'
... #depict some buttons and links
books_controller.rb
class BooksController < ApplicationController
expose(:book, attributes: :book_params, finder_parameter: :id)
expose_decorated(:book, decorator: BookDecorator)
...
I've followed these tutorials (https://github.com/netguru/decent_decoration https://github.com/drapergem/draper#decorating-objects) and it seems to be fine, but when i'm on books index page, it says
undefined method `in_users_list?' for Book:0x007f6f4a0a4a18
I suppose that it still doesn't know that it should use method from decorator, but how to fix it? I can't understand what I've done wrong, please help to find and fix problem!
Thank you in advance!

Well, I just had to add expose_decorated(:books) in books_controller. I thing that it's because I'm using it in index method, so books (not just book) should be decorated

Related

rails - instance model include module on variable condition

I need to know if I can include a module to an instantiated model.
What works today :
in the controller
#m = MyModel.create(params)
in the model
class Doc < ActiveRecord::Base
after_save :set_include
def set_include
if bool
self.class.send(:include, Module1)
else
self.class.send(:include, Module2)
end
end
end
and this works, but I'm afraid that self.class actually include the module for the class model an not the instantiated model
In this case, this will work.
The module methods are call after the object is saved.
But in many case, the controller will call some modules methods.
I thought of called the method set_include (up there) in a before_action of the controller.
But I really thinks that is not a good idea...
Any idea how I can really do that with in a good way ?
thanks !
Answer to your direct question is no. Your code only appears to be working and is actually not modifying instance of a class, but the class itself. So all instances of it will be getting this "benefit". Probably not what you wanted. Let me demonstrate with simple ruby example: https://repl.it/BnLO
What you can do instead is use extend with instance like: https://repl.it/BnLO/2
Applied to your code it would be:
class Doc < ActiveRecord::Base
after_save :set_include
def set_include
if bool
extend(Module1)
else
extend(Module2)
end
end
end
Also, self is not necessary. https://repl.it/BnLO/3
You need to use instance class (a.k.a eigenklass):
def set_include
singleton_class.instance_eval do
include bool ? Module1 : Module2
end
end
However the fact that you want to do this is suspicious and might lead to a disaster. So the question is: what are you really trying to achieve here - there surely is the better way of doing so.

custom link_to - ruby on rails

I have a class Thingy, whose objects often need to create links to other websites. So far the only approach working for me is the following:
class Thingy < Active:Record::Base
def makeLink
result = ""+self.secondProperty+""
end
...
Now in any view I could use this link-method as follows
thingy.makeLink.html_safe
Somehow I feel there should be a much better way. What is the right approach here?
the proper approach would be to add a ThingyHelper in app/helpers
def behavior_describing_method_name(thingy)
link_to thingy.secondProperty, "someUrl#{thingy.firstProperty}"
end

Create an action with a class method in Rails

I would like to create a custom action inside a controller with a class method. But is it possible ?
I would look like:
class HellosController < ActionController::Base
def self.index
end
end
The problem then is that, how can we access it... I tried this:
get 'hello/' => 'hellos.index'
But it's not a success.
ArgumentError: Missing :action key on routes definition, please check your routes.
I know it is not from the Rails conventions, but if you have some ideas, you're welcome.
Seems like a bad idea, or at least unconventional, to use a class method this way in a controller, but you could try something like this ..
class HellosController < ActionController::Base
def self.index
end
def index
self.class.index
end
end
Don't say I didn't warn you when you try to start using instance variables :)

The best way to “split” up a large Rails controller

I currently have an already-large controller that’s getting bigger. I was wondering what would be the best way to slim down my controllers. I’m not necessarily looking for the easiest way, but a safe and efficient way. I’ve been developing with Rails for a while now but I’m still not familiar with how “subclassing” works and I’m not even sure if it’s supposed to be used in this way. I was thinking maybe something like this?
class SomeController < ApplicationController
end
class MoreFunctionsController < SomeController
end
That’s currently untested – I’m still working on it right now – but I hope that this would sort of give you an idea of what direction I’m trying to go. I’m also not sure how the routing for this would look. What would be the best way to “split” up a large controller?
ActiveSupport::Concern (documentation) is what you are looking for.
Update
Something like this:
# config/application.rb
config.autoload_paths += %W(#{Rails.root}/app/controllers/concerns) # in Rails4 this is automatic
# app/controllers/my_controller.rb
class MyController < ApplicationController
include GeneralStuffConcern
def index
render text: foo
end
end
# app/controllers/concerns/general_stuff_concern.rb
module GeneralStuffConcern
extend ActiveSupport::Concern
def show
redirect_to root_path
end
protected
def foo
'fooo'
end
end
update 2
I actually recommend this more http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
update 3 (2022)
Bounded contexts https://blog.eq8.eu/article/rails-bounded-contexts.html

How to put many Model classes together in one Module to use in Rails

In rails i have a lot of tables and need to define a lot of Model classes to use for controller, but i want to put all the model classes into one module file, and then make controller to use the model class in the module, but i don't know how to do it.
Could someone give me help on the problem? Appreciate your help very much.
app/models/widgets/blue_widget.rb
class Widgets::BlueWidget < ActiveRecord::Base
// etc.
end
app/controllers/blue_widget_controller.rb
def index
#widgets = Widgets::BlueWidget.all
end
You can also namespace the controllers.
Edit:
lib/widgets.rb
module Widgets
class BlueWidget
end
class RedWidget
end
end
controller:
require 'lib/widgets'
def index
#widgets = Widgets::BlueWidget.all
end
Is that what you mean?
You can also generate models directly in subdirectorys and get them im modules:
rails g model user/likes name:string like:boolean
and you will get your generated files.
The generated model would be in app/models/user/likes.rb
class User::Likes < ActiveRecord::Base
end

Resources