Rails Active Storage and Acts as List - ruby-on-rails

I've been working on a way to add acts_as_list to ActiveStorage::Attachment using a concern. I've been working on this for two days and can't seem to find a way to add the line acts_as_list to the model. I tried to load with an initializer. Any thoughts?
Here's the initializer code:
Rails.configuration.to_prepare do
class ActiveStorage::Attachment
include ActiveStorageActsAsList
end
end
Concern
module ActiveStorageActsAsList
extend ActiveSupport::Concern
included do
acts_as_list
end
end

Related

How to get all Users using a Plugin in Redmine/Ruby on Rails?

I'm coding a Plugin for Redmine in Ruby on Rails atm.
I need to get all "Users" to link them to a "Skill". So I need
all users to make a relationship to my skills. As it is a plugin, I don't want to write in the
main users model in Redmine. So, I kinda want to extend or something the original user model.
Anyone has a clue how I can solve this?
If you want to add logic to an already existing class (like adding new methods, relationships, validations, etc..), you can do it with Ruby Module#class_eval:
User.class_eval do
# Inside this block we add the new logic that we want to add to the User class
def new_method
end
end
To patch models in Redmine I used to use this approach:
# plugins/your_plugin_name/lib/your_plugin_name/user_path.rb
module YourPluginName
module UserPatch
extend ActiveSupport::Concern
included do
has_many :skills
end
def some_new_method
end
end
end
User.include YourPluginName::UserPatch

How to make a plain ruby object assignable as active record association

I have an Audit class which is backed by ActiveRecord.
class Audit < ActiveRecord::Base
belongs_to :user, polymorphic: true
end
I have a User class which is a plain ruby object with some ActiveModel functionality included. It's not a database model because my users are actually stored in a different database and served over an API.
class User
include ActiveModel::Conversion
include ActiveModel::Validations
extend ActiveModel::Naming
def self.primary_key
'id'
end
def id
42
end
def persisted?
false
end
end
I'm trying to assign a user to an audit like this:
audit = Audit.new
audit.user = User.new
audit.save!
From a data perspective, this should work ok. To define a polymorphic association, we need to put values into two columns on the audits table. We can set audits.user_id to the value 42 and audits.user_type to the string "User".
However, I hit an exception:
undefined method `_read_attribute' for #<User:0x007f85faa49520 #attributes={"id"=>42}> (NoMethodError)
active_record/associations/belongs_to_polymorphic_association.rb:13:in `replace_keys'
I traced that back to the ActiveRecord source and it seems to be defined here. Unfortunately, the fact that it's ActiveRecord rather than ActiveModel means that I can't include that mixin into my class.
I tried defining my own _read_attribute method but I go down a rabbit hole of having to redefine more and more ActiveRecord functionality like AttributeSet and so on.
I also realise that I can workaround the problem by assigning Audit#user_type and Audit#user_id. That is unsatisfactory however because, in reality, I would have to fork a gem and edit it to do that.
How can I modify my User class so that I can cleanly assign it to an audit.
P.S. Here's a sample app so you can try this yourself.
Instead of hacking deeper and deeper to replicate ActiveRecord functionality, you may want to consider actually inheriting from ActiveRecord::Base instead of including ActiveModel. Your only constraint is that you don't have a table. There's a gem for that:
activerecord-tableless
This class works with your sample app:
require 'active_record'
require 'activerecord-tableless'
class User < ActiveRecord::Base
has_no_table
# required so ActiveRecord doesn't try to create a new associated
# User record with the audit
def new_record?
false
end
def id
42
end
end

ActiveSupport::Concern and extending mongoid model

I am using mongoid with rails 3 and have come lately to a very tough
problem and I need an advice.
I am working on a CMS and one of the ideas was that CMS would provide
some basic models definitions and end user would, if needed, extend
basic class with its own definitions and controls and save them in different collections (tables).
class DcPage
include Mongoid::Document
field a ....
belongs_to b ....
validates a ....
end
class MyPage < DcPage
field c ....
validates c ....
end
Up until last version of mongoid this worked (with little hack) and data
would be saved to my_pages collection. Because of some problem, mongoid no
longer support this behaviour and data always gets saved to dc_pages
collection.
When explaining my problem, mongoid team suggested that I use
ActiveSupport::Concern and provided me with an example. Which works
perfectly OK if extended class is defined in same source file. Which
btw. never happens in praxis.
module CommonBehaviour
extend ActiveSupport::Concern
included do
field :subject, type: String, default: ''
# ...
end
end
class DcPage
include Mongoid::Document
include CommonBehaviour
end
class MyPage
include Mongoid::Document
include CommonBehaviour
end
So far I have found out that it works if I require basic source file in
my second file. Which looks like this:
require '/some/path/to/my/gem/app/models/dc_page.rb
Can you can see my pain now. Basic source file would of course be backed into
gem and therefor becomes a moving target.
Please help me with better solution.
by
TheR
The reason this doesn't work is because this is the pattern for single table inheritance.
You would need to turn off table inheritance in order for this to work.
However, the suggestion from the mongoid devs is the correct route to go in this case.
It looks like you just need to require your module/classes correctly.

How to add custom model modifier like in most gems?

I want to DRY some model functionality like in a lot of gems.
For example in gem acts-as-taggable-on we should just add acts_as_taggable to any model to enable tagging on it.
How I can add my own include_god_mode model modifier into my rails project?
So I found out that it is implemented by simple class extending and mixing.
For example in the acts-as-taggable-on gem there are a lot of modules which included into ActiveRecord::Base so acts_as_taggable in a model is just a syntax sugar.
Here is acts-as-taggable-on sources with including:
if defined?(ActiveRecord::Base)
ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger
end
if defined?(ActionView::Base)
ActionView::Base.send :include, ActsAsTaggableOn::TagsHelper
end
So if I want to add such sugar to my model I need to include a method into ActiveRecord::Base (or similar superclass in case of ActiveRecord ORM) that will include module with my stuff.

Rails inheritance for classes of same behaviour but different attributes

I have been researching on the best approach for my problem which I originally had implemented as a single table inheritance but am deeply concerned about the scalability, as potentially will have thousands of columns in the table.
So the problem is I would like to have products which the methods of each are exactly the same the only difference being the attributes each one contains. It seems that in this situation that mutli-class inheritance (not supported natively in rails?) would be the best approach or some sort of polymorphic associations.
I want to work towards the following
#product.rb
Class Product < ActiveRecord::Base
attr_accessible :title .....
def to_s # some arbitrary method used by all extending classes
....
end
end
#book.rb
class Book < Product
attr_accessible :author...
end
So I want the book to inherit the methods from product and not for the product to know about the attributes required by each subclass. And if possible get all of the products through one query.
I need to know the best way of approaching this, and if I am doing it completely wrong, please note the code written above is just for example to simplify my problem.
What you can do is create a module and include it in several different models.
First, create a file in your lib directory
i.e.) my_module.rb
module MyModule
def full_name
"#{first_name} #{last_name}"
end
end
Then, make sure the module is loaded when your Rails App starts:
In config/application.rb:
config.autoload_paths += %W(#{config.root}/lib)
Finally, include it in your models:
i.e.) app/models/thing.rb
class Thing < ActiveRecord::Base
attr_accessible :first_name, :last_name
include AdditionMod
end
You can test it in the console:
#thing = Thing.create(first_name: "Awesome", last_name: "Module")
#thing.full_name
=> "Awesome Module"
Found out that I can use H-store in conjunction with postgres that allows me to have a column that contains a schema less hash that can be used with the power of postgres (for an example take a look at http://hstoredemo.herokuapp.com/)

Resources