Rails Object để băm


147

Tôi có đối tượng sau đây đã được tạo

@post = Post.create(:name => 'test', :post_number => 20, :active => true)

Khi điều này được lưu, tôi muốn có thể đưa đối tượng trở lại hàm băm, ví dụ bằng cách thực hiện một số thứ như:

@object.to_hash

Làm thế nào điều này có thể từ bên trong đường ray?

Câu trả lời:


294

Nếu bạn đang tìm kiếm chỉ các thuộc tính, thì bạn có thể nhận được chúng bằng cách:

@post.attributes

30
Đừng sử dụng điều này khi lặp, phương pháp tốn kém . Đi với as_json
AnkitG

5
.to_jsonsẽ truy vấn DB nếu mô hình chưa hoàn thành
ykhrustalev

1
Hoạt động với joinsselect, Person.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributessẽ trở lại { street: "", name: "" }
fangxing

3
@AnkitG Tôi không tin as_json rẻ hơn. Nếu bạn nhìn vào mã nguồn as_json, nó sẽ gọi serializable_hash, lần lượt, sẽ gọi attributes! Vì vậy, lời khuyên của bạn là thực sự thêm hai lớp phức tạp hơn attributes, làm cho nó thậm chí còn đắt hơn.
sandre89

2
.as_jsonsẽ tuần tự hóa đối tượng để băm ruby
roadev 15/03/19

45

Trong hầu hết các phiên bản Rails gần đây (không thể biết chính xác cái nào), bạn có thể sử dụng as_jsonphương thức:

@post = Post.first
hash = @post.as_json
puts hash.pretty_inspect

Sẽ xuất:

{ 
  :name => "test",
  :post_number => 20,
  :active => true
}

Để đi xa hơn một chút, bạn có thể ghi đè phương thức đó để tùy chỉnh cách xuất hiện các thuộc tính của bạn, bằng cách thực hiện như sau:

class Post < ActiveRecord::Base
  def as_json(*args)
    {
      :name => "My name is '#{self.name}'",
      :post_number => "Post ##{self.post_number}",
    }
  end
end

Sau đó, với cùng một ví dụ như trên, sẽ xuất ra:

{ 
  :name => "My name is 'test'",
  :post_number => "Post #20"
}

Tất nhiên điều này có nghĩa là bạn phải xác định rõ ràng thuộc tính nào phải xuất hiện.

Hi vọng điêu nay co ich.

BIÊN TẬP :

Ngoài ra, bạn có thể kiểm tra đá quý Hashifiable .


OP đã không yêu cầu JSON, nhưng cho một hàm băm.
David Hempy

5
@DavidHempy Vui lòng đọc kỹ câu trả lời của tôi trước khi bỏ phiếu. Như tôi đã trình bày trong các ví dụ của mình, đây chính xác là những gì #as_json làm và được dành cho: api.rubyonrails.org/groupes/ActiveModel/Serialulators/ . Tôi đã không chọn tên của phương pháp đó.
Raf

25
@object.as_json

as_json có cách rất linh hoạt để cấu hình đối tượng phức tạp theo quan hệ mô hình

THÍ DỤ

Chiến dịch mô hình thuộc về cửa hàng và có một danh sách

Danh sách mô hình có nhiều list_t task và mỗi list_t Nhiệm vụ có nhiều bình luận

Chúng ta có thể nhận được một json kết hợp tất cả các dữ liệu đó một cách dễ dàng.

@campaign.as_json(
    {
        except: [:created_at, :updated_at],
        include: {
            shop: {
                except: [:created_at, :updated_at, :customer_id],
                include: {customer: {except: [:created_at, :updated_at]}}},
            list: {
                except: [:created_at, :updated_at, :observation_id],
                include: {
                    list_tasks: {
                        except: [:created_at, :updated_at],
                        include: {comments: {except: [:created_at, :updated_at]}}
                    }
                }
            },
        },
        methods: :tags
    })

Các phương thức thông báo :: thẻ có thể giúp bạn đính kèm bất kỳ đối tượng bổ sung nào không có quan hệ với người khác. Bạn chỉ cần xác định một phương thức với các thẻ tên trong chiến dịch mô hình . Phương thức này sẽ trả về bất cứ thứ gì bạn cần (ví dụ: Tags.all)

Tài liệu chính thức cho as_json


Đã thực hiện một chức năng tùy chỉnh ngay trước khi tìm thấy điều này. Muốn có nhiều hơn một phương thức sử dụng, thay vì xác định hàm cho lớp. Đã bỏ lỡ điều này ngay cả sau khi làm việc với các phương thức tuần tự hóa XML vì một số lý do. Các to_biến thể dường như hoạt động gần như chính xác như các as_biến thể, ngoại trừ đầu ra được trích dẫn. Điều duy nhất tôi không thích là không duy trì thứ tự các tiêu chí lọc của mình. Nó dường như được sắp xếp theo thứ tự abc. Tôi nghĩ rằng nó có liên quan đến viên ngọc tuyệt vời mà tôi có trong môi trường của mình, nhưng tôi không nghĩ đó là trường hợp.
Pysis

8

Bạn có thể lấy các thuộc tính của một đối tượng mô hình được trả về dưới dạng băm bằng cách sử dụng một trong hai

@post.attributes

hoặc là

@post.as_json

as_jsoncho phép bạn bao gồm các liên kết và các thuộc tính của chúng cũng như chỉ định các thuộc tính cần bao gồm / loại trừ (xem tài liệu ). Tuy nhiên, nếu bạn chỉ cần các thuộc tính của đối tượng cơ sở, thì điểm chuẩn trong ứng dụng của tôi với ruby ​​2.2.3 và rails 4.2.2 chứng tỏ rằng attributescần ít hơn một nửa thời gian as_json.

>> p = Problem.last
 Problem Load (0.5ms)  SELECT  "problems".* FROM "problems"  ORDER BY "problems"."id" DESC LIMIT 1
=> #<Problem id: 137, enabled: true, created_at: "2016-02-19 11:20:28", updated_at: "2016-02-26 07:47:34"> 
>>
>> p.attributes
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> p.as_json
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> n = 1000000
>> Benchmark.bmbm do |x|
?>   x.report("attributes") { n.times { p.attributes } }
?>   x.report("as_json")    { n.times { p.as_json } }
>> end
Rehearsal ----------------------------------------------
attributes   6.910000   0.020000   6.930000 (  7.078699)
as_json     14.810000   0.160000  14.970000 ( 15.253316)
------------------------------------ total: 21.900000sec

             user     system      total        real
attributes   6.820000   0.010000   6.830000 (  7.004783)
as_json     14.990000   0.050000  15.040000 ( 15.352894)

as_json sẽ gọi lại truy vấn cơ sở dữ liệu, nếu bạn đang chạy resouce lồng nhau với tham gia metho
Tony Hsieh

6

Có một số gợi ý tuyệt vời ở đây.

Tôi nghĩ rằng đáng chú ý là bạn có thể coi mô hình ActiveRecord như một hàm băm như vậy:

@customer = Customer.new( name: "John Jacob" )
@customer.name    # => "John Jacob"
@customer[:name]  # => "John Jacob"
@customer['name'] # => "John Jacob"

Do đó, thay vì tạo ra một hàm băm của các thuộc tính, bạn có thể sử dụng chính đối tượng làm hàm băm.


6

Bạn chắc chắn có thể sử dụng các thuộc tính để trả về tất cả các thuộc tính nhưng bạn có thể thêm một phương thức cá thể vào Đăng, gọi nó là "to_hash" và để nó trả về dữ liệu bạn muốn trong hàm băm. Cái gì đó như

def to_hash
 { name: self.name, active: true }
end

2

không chắc chắn nếu đó là những gì bạn cần nhưng hãy thử điều này trong bảng điều khiển ruby:

h = Hash.new
h["name"] = "test"
h["post_number"] = 20
h["active"] = true
h

rõ ràng nó sẽ trả về cho bạn một hàm băm trong giao diện điều khiển. nếu bạn muốn trả về hàm băm từ bên trong một phương thức - thay vì chỉ "h" hãy thử sử dụng "return h.inspect", một cái gì đó tương tự như:

def wordcount(str)
  h = Hash.new()
  str.split.each do |key|
    if h[key] == nil
      h[key] = 1
    else
      h[key] = h[key] + 1
    end
  end
  return h.inspect
end

Poster đang hỏi về các mô hình ActiveRecord trong Rails.
Jeffrey Harrington

2

Giải pháp của tôi:

Hash[ post.attributes.map{ |a| [a, post[a]] } ]

0

Câu trả lời của Swanand rất hay.

nếu bạn đang sử dụng FactoryGirl, bạn có thể sử dụng buildphương thức của nó để tạo hàm băm mà không cần khóa id. ví dụ

build(:post).attributes

0

Câu hỏi cũ, nhưng được tham khảo nhiều ... Tôi nghĩ rằng hầu hết mọi người sử dụng các phương pháp khác, nhưng vẫn còn nguyên một to_hashphương pháp, nó phải được thiết lập ngay. Nói chung, pluck là một câu trả lời tốt hơn sau khi rails 4 ... trả lời điều này chủ yếu là vì tôi đã phải tìm kiếm một bó để tìm chủ đề này hoặc bất cứ điều gì hữu ích và giả sử những người khác đang gặp vấn đề tương tự ...

Lưu ý: không khuyến nghị điều này cho tất cả mọi người, nhưng trường hợp cạnh!


Từ viên ruby ​​trên đường ray api ... http://api.rubyonrails.org/groupes/ActiveRecord/Result.html ...

This class encapsulates a result returned from calling #exec_query on any database connection adapter. For example:

result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
result # => #<ActiveRecord::Result:0xdeadbeef>

...

# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
      {"id" => 2, "title" => "title_2", "body" => "body_2"},
      ...
     ] ...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.