Ruact::Serializable
Ruact::Serializable is a mixin that lets you declare exactly which attributes of a Ruby object are safe to send to the browser as React props.
Why you need it
Section titled “Why you need it”When you pass a Ruby object as a prop to a client component, ruact needs to serialize it to JSON. By default it calls as_json, which may expose internal fields, timestamps, or sensitive data you did not intend to send.
Ruact::Serializable gives you an explicit allowlist via ruact_props:
class Post < ApplicationRecord include Ruact::Serializable
ruact_props :id, :title, :body # :admin_notes, :internal_score, etc. are never sent to the browserendBasic usage
Section titled “Basic usage”class Post < ApplicationRecord include Ruact::Serializable
ruact_props :id, :title, :body, :created_atendUse in an ERB template:
<PostCard post={@post} />The browser receives only { id: 1, title: "Hello", body: "...", created_at: "..." } — nothing else.
Works with any Ruby object
Section titled “Works with any Ruby object”Ruact::Serializable is not limited to ActiveRecord models. Include it in any Ruby class:
class UserPresenter include Ruact::Serializable
attr_reader :id, :display_name, :avatar_url, :role
ruact_props :id, :display_name, :avatar_url, :role
def initialize(user) @id = user.id @display_name = user.full_name @avatar_url = user.avatar.url @role = user.admin? ? "admin" : "member" endend<UserCard user={UserPresenter.new(@user)} />ruact_props validates loudly — timing depends on the class
Section titled “ruact_props validates loudly — timing depends on the class”If you declare a prop that does not correspond to a defined method, ruact raises a clear ArgumentError naming the offending name:
class UserPresenter include Ruact::Serializable
attr_reader :id, :name ruact_props :id, :name, :nonexistent_method # => ArgumentError: ruact_props: method `nonexistent_method` is not defined on UserPresenterendThe loud check always happens; only when it fires depends on the class:
- Plain Ruby objects (POROs) are checked at class load time — a typo or missing accessor raises the moment the class is loaded, at startup rather than at render time.
- ActiveRecord models define their attribute reader methods lazily (on first access), so at the moment
ruact_props :titleruns the reader for a real column does not exist yet. To avoid rejecting a valid model at boot — and to avoid a database connection at class load — ruact defers the check for an AR model to the first serialize. A valid model boots; a bogus prop name still raises the same cleanArgumentErrorthe first time that model is rendered.
Either way the guarantee is the same: a typo’d or missing prop fails loudly, never silently.
Nested serializable objects
Section titled “Nested serializable objects”Props can be nested. If a declared prop returns another object that includes Ruact::Serializable, it is serialized recursively using its own ruact_props declaration:
class Author < ApplicationRecord include Ruact::Serializable ruact_props :id, :nameend
class Post < ApplicationRecord include Ruact::Serializable ruact_props :id, :title, :author
belongs_to :authorend<PostCard post={@post} /># Sends: { id: 1, title: "Hello", author: { id: 5, name: "Alice" } }Strict serialization mode
Section titled “Strict serialization mode”When config.strict_serialization = true, any object passed as a prop that does not include Ruact::Serializable raises Ruact::SerializationError.
This is the recommended production setting. It prevents passing raw ActiveRecord objects (which would call as_json) and ensures all prop surfaces are explicitly declared.
Ruact.configure do |config| config.strict_serialization = Rails.env.production?endruact_props vs as_json
Section titled “ruact_props vs as_json”ruact_props |
as_json |
|
|---|---|---|
| Explicit allowlist | ✅ Yes | ❌ No — serializes all attributes |
| Works on POROs and ActiveRecord models | ✅ Yes | ✅ Yes |
| Validated loudly for typos/missing accessors | ✅ Yes (POROs at load, AR at first serialize) | ❌ No |
| Enforced in strict mode | ✅ Yes | ❌ Raises in strict mode |
| Nested serialization | ✅ Recursive | ✅ Recursive (via as_json chain) |
ruact_props(*attrs)
Section titled “ruact_props(*attrs)”Class method — declares the attributes that are safe to serialize.
ruact_props :id, :name, :emailattrs— one or moreSymbolnames. Each must correspond to a reader method on the class (anattr_reader, a plain method, or an ActiveRecord column).- Raises
ArgumentErrorfor an undefined name — at class load for a PORO, at first serialize for an ActiveRecord model (whose readers are defined lazily). Either way it fails loudly. - Returns the list of declared props.
ruact_serialize
Section titled “ruact_serialize”Instance method — returns a Hash of the declared props and their current values.
post = Post.find(1)post.ruact_serialize # => { id: 1, title: "Hello", body: "..." }This is what ruact calls internally when serializing the object. You generally do not need to call it directly.