Module: ActiveModel::Datastore
- Extended by:
- ActiveSupport::Concern
- Includes:
- NestedAttr, TrackChanges, Dirty, Model, Validations, Validations::Callbacks
- Defined in:
- lib/active_model/datastore.rb,
lib/active_model/datastore/version.rb,
lib/active_model/datastore/nested_attr.rb,
lib/active_model/datastore/track_changes.rb,
lib/active_model/datastore/errors.rb
Overview
Active Model Datastore
Makes the google-cloud-datastore gem compliant with active_model conventions and compatible with your Rails 5+ applications.
Let’s start by implementing the model:
class User
include ActiveModel::Datastore
attr_accessor :email, :name, :enabled, :state
before_validation :set_default_values
before_save { puts '** something can happen before save **' }
after_save { puts '** something can happen after save **' }
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }
validates :name, presence: true, length: { maximum: 30 }
def entity_properties
%w[email name enabled]
end
def set_default_values
default_property_value :enabled, true
end
def format_values
format_property_value :role, :integer
end
end
Using ‘attr_accessor` the attributes of the model are defined. Validations and Callbacks all work as you would expect. However, `entity_properties` is new. Data objects in Google Cloud Datastore are known as entities. Entities are of a kind. An entity has one or more named properties, each of which can have one or more values. Think of them like this:
-
‘Kind’ (which is your table)
-
‘Entity’ (which is the record from the table)
-
‘Property’ (which is the attribute of the record)
The ‘entity_properties` method defines an Array of the properties that belong to the entity in cloud datastore. With this approach, Rails deals solely with ActiveModel objects. The objects are converted to/from entities as needed during save/query operations.
We have also added the ability to set default property values and type cast the format of values for entities.
Now on to the controller! A scaffold generated controller works out of the box:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
@users = User.all
end
def show
end
def new
@user = User.new
end
def edit
end
def create
@user = User.new(user_params)
respond_to do |format|
if @user.save
format.html { redirect_to @user, notice: 'User was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if @user.update(user_params)
format.html { redirect_to @user, notice: 'User was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
end
end
private
def set_user
@user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:email, :name)
end
end
Defined Under Namespace
Modules: ClassMethods, NestedAttr, TrackChanges Classes: EntityError, EntityNotSavedError, Error, TrackChangesError
Constant Summary collapse
- VERSION =
'0.1.0'
Instance Method Summary collapse
-
#build_entity(parent = nil) ⇒ Entity
Builds the Cloud Datastore entity with attributes from the Model object.
-
#default_property_value(attr, value) ⇒ Object
Sets a default value for the property if not currently set.
- #destroy ⇒ Object
- #entity_properties ⇒ Object
-
#format_property_value(attr, type) ⇒ Object
Converts the type of the property.
-
#persisted? ⇒ Boolean
Used by ActiveModel for determining polymorphic routing.
- #save(parent = nil) ⇒ Object
-
#save! ⇒ Object
For compatibility with libraries that require the bang method version (example, factory_girl).
- #update(params) ⇒ Object
Methods included from TrackChanges
#exclude_from_save?, #reload!, #remove_unmodified_children, #tracked_attributes, #values_changed?
Methods included from NestedAttr
#assign_nested_attributes, #mark_for_destruction, #marked_for_destruction?, #nested_attributes?, #nested_errors, #nested_model_class_names, #nested_models
Instance Method Details
#build_entity(parent = nil) ⇒ Entity
Builds the Cloud Datastore entity with attributes from the Model object.
182 183 184 185 186 187 188 189 |
# File 'lib/active_model/datastore.rb', line 182 def build_entity(parent = nil) entity = CloudDatastore.dataset.entity self.class.name, id entity.key.parent = parent if parent.present? entity_properties.each do |attr| entity[attr] = instance_variable_get("@#{attr}") end entity end |
#default_property_value(attr, value) ⇒ Object
Sets a default value for the property if not currently set.
Example:
default_property_value :state, 0
is equivalent to:
self.state = state.presence || 0
Example:
default_property_value :enabled, false
is equivalent to:
self.enabled = false if enabled.nil?
148 149 150 151 152 153 154 |
# File 'lib/active_model/datastore.rb', line 148 def default_property_value(attr, value) if value.is_a?(TrueClass) || value.is_a?(FalseClass) send("#{attr.to_sym}=", value) if send(attr.to_sym).nil? else send("#{attr.to_sym}=", send(attr.to_sym).presence || value) end end |
#destroy ⇒ Object
222 223 224 225 226 227 |
# File 'lib/active_model/datastore.rb', line 222 def destroy run_callbacks :destroy do key = CloudDatastore.dataset.key self.class.name, id self.class.retry_on_exception? { CloudDatastore.dataset.delete key } end end |
#entity_properties ⇒ Object
122 123 124 |
# File 'lib/active_model/datastore.rb', line 122 def entity_properties [] end |
#format_property_value(attr, type) ⇒ Object
Converts the type of the property.
Example:
format_property_value :weight, :float
is equivalent to:
self.weight = weight.to_f if weight.present?
165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/active_model/datastore.rb', line 165 def format_property_value(attr, type) return unless send(attr.to_sym).present? case type.to_sym when :float send("#{attr.to_sym}=", send(attr.to_sym).to_f) when :integer send("#{attr.to_sym}=", send(attr.to_sym).to_i) else raise ArgumentError, 'Supported types are :float, :integer' end end |
#persisted? ⇒ Boolean
Used by ActiveModel for determining polymorphic routing.
129 130 131 |
# File 'lib/active_model/datastore.rb', line 129 def persisted? id.present? end |
#save(parent = nil) ⇒ Object
191 192 193 |
# File 'lib/active_model/datastore.rb', line 191 def save(parent = nil) save_entity(parent) end |
#save! ⇒ Object
For compatibility with libraries that require the bang method version (example, factory_girl). If you require a save! method that supports parents (ancestor queries), override this method in your own code with something like this:
def save!
parent = nil
if account_id.present?
parent = CloudDatastore.dataset.key 'Parent' + self.class.name, account_id.to_i
end
msg = 'Failed to save the entity'
save_entity(parent) || raise(ActiveModel::Datastore::EntityNotSavedError, msg)
end
209 210 211 |
# File 'lib/active_model/datastore.rb', line 209 def save! save_entity || raise(EntityNotSavedError, 'Failed to save the entity') end |
#update(params) ⇒ Object
213 214 215 216 217 218 219 220 |
# File 'lib/active_model/datastore.rb', line 213 def update(params) assign_attributes(params) return unless valid? run_callbacks :update do entity = build_entity self.class.retry_on_exception? { CloudDatastore.dataset.save entity } end end |