Better Code Structure for Rails Associations

Stage

Let's talk about the most common type of association we encounter.

I have a user who :has_manyPost (s)

class User < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
end

Problem Statement

I want to do some (very easy and fast) processing on all user posts. I am looking for the best way to structure my code to achieve it. Below are a few ways and why they work or do not work.

Method 1

Do it in the class itself User.

class User < ActiveRecord::Base
  has_many :posts

  def process_posts
    posts.each do |post|
      # code of whatever 'process' does to posts of this user
    end
  end
end

The post class remains the same:

class Post < ActiveRecord::Base
  belongs_to :user
end

This method is called:

User.find(1).process_posts

Why is this not the best way to do this

- Post. :has_many , . orders, comments, children ..

User process_orders, process_comments, process_children (yikes), , ( ) , .. .

2

-

/ User, . , all .

3

User.

class User < ActiveRecord::Base
  has_many :comments
  # all target specific code in target classes
end

class Post < ActiveRecord::Base
  belongs_to :user

  # Class method
  def self.process
    Post.all.each do |post|  # see Note 2 below
      # code of whatever 'process' does to posts of this user
    end
  end
end

:

User.find(1).posts.process   # See Note 1 below

, 1 2, :

  • .
  • process process_posts. process : User.find(1).orders.process .. User.find(1).process_orders ( 1).

1:

, , . . TL; DR - , User.find(1).posts CollectionProxy, (Post) . scope_attributes, user_id , posts.process. . . 2 .

2:

, , , Post.all.each , , .

, User.find(99).posts.process, Post.all :

SELECT "notes".* FROM "posts" WHERE "posts"."user_id" = $1  [["user_id", 99]]

ID : 99.

@Jesuspc , Post.all.each all.each. , .

,

  • , . ? 3 .
+4
4

. :

class PostProcessor
  def initialize(posts)
    @posts = posts
  end

  def process
    @posts.each do |post|
      # ...
    end
  end
end

PostProcessor.new(User.find(1).posts).process

Service Object. , . "" : http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

+3

, 1 . - :

Class User < ActiveRecord::Base
  has_many :posts

  def process_posts
    posts.each do |post|
     post.process
    end
  end
end

process Post ( ):

Class Post < ActiveRecord::Base
  belongs_to :user

  def process
     # Logic of your Post process
  end
end

, Post Post. User "" , . , .

3 , ( ).

. , , eager loading ActiveRecord, .

+1

User - Post (, , process User):

#app/models/post.rb
class Post < ActiveRecord::Base
    def process
       return false if post.published?
       # do something
    end
end

ActiveRecord Association User:

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :posts do
      def process
          proxy_association.target.each do |post|
             post.process
          end
      end
   end
end

...

@user = User.find 1
@user.posts.process
+1

, .

ActiveRecord . , ( ) . , ActiveRecord:: Base . , , ActiveRecord , , :

User.find(1).posts.process

, , ActiveRecord , ( ). , , .

, , , ProcessablePostsCollection ( Processable , , , , PostsCollection), , SimpleDelegator .

class ProcessablePostsCollection < SimpleDelegator
  def self.from_collection(collection)
    new collection
  end

  def initialize(source)
    super source
  end

  def process
    # code of whatever 'process' does to posts
  end
end

:

ProcessablePostsCollection.from_collection(User.find(1).posts).process

from_collection .

, , , . find_in_batches ActiveRecord:: Relation.

, , . , , , , Rails , , , , ActiveRecord.

0

Source: https://habr.com/ru/post/1623143/


All Articles