-
Notifications
You must be signed in to change notification settings - Fork 276
Neo4j::Rails Persistence
The Neo4j::Rails::Model
and Neo4j::Rails::Relationship
implements the Rails ActiveModel interface and a subset of the ActiveRecord API.
Example:
class IceCream < Neo4j::Rails::Model
property :flavour
validates_presence_of :flavour
end
IceCream.new.valid? # => false
IceCream.new(:flavour => "vanilla").valid? # => true
A Neo4j::Rails::Model wraps a Neo4j::Node. The Neo4j::Rails::Model
and Neo4j::Rails::Relationship
are Active Model compliant and does implement some Active Record method.
The following callbacks are defined: initialize, valid?, create_or_update, create, update, destroy. See the rails documentation when they are called.
There is also support for Active Model observers, see Neo4j::Rails::Observer and neo4j-observers-example
The Neo4j::Model.new
methods does not require a transaction (unlike the Neo4j::Node.new
method)
since it creates a node in memory with no connection to the neo4j database. This makes it easier to create forms that don’t touch the database if validation fails by using the ActiveRecord-style two-step Model.new
+ Model#save
creation. The node will be saved to the database when the save
method is called.
Saves the node if the validation was successful. It will create a new transaction if neccessarly.
Notice, nested nodes will also be saved and validated (see below – does raise exception !). Validation can be skipped by model.save( :validate => false )
Updates the model with the given attributes and saves the model if the validation is successful. Will create a new transaction if neccessarly.
The Neo4j::Rails::Model#property
and Neo4j::Rails::Relationship#property
method accept additional configuration parameters:, :default
, :length
and :null
and :type
and converter
, see Neo4j::Rails::Attributes::ClassMethods#property
Example:
class MyModel < Neo4j::Rails::Model
# gives title "Mr" unless it is set specifically
# ensures it is a maximum of 3 chars long
# ensures it is never saved with a nil value
property :title, :default => "Mr", :limit => 3, :null => false
property :superuser, :foo, :type => :boolean # both superuser and foo will be converted to true/false values
end
All the normal validations work for both Neo4j::Rails::Model
and Neo4j::Rails::Relationship
Example:
class Person < Neo4j::Rails::Model
property :email, :index => :exact
validates :email, :uniqueness => true, :allow_blank => false
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
end
In order to get uniquess validation to work you must have an exact index on the property, as shown above (index :email).
Notice If you are saving a node which has changed relationships/nodes an exception will be thrown if they are not valid !
Notice It is not enought to have a unique validation to make sure nodes and relationships are unique, see below.
If you want to be 100% sure of having unique nodes or relationship it is not enough with a unique validation on the property (since of possible concurrency issues). Instead, you should declare the property with a :unique => true
and use the get_or_create
method, see below:
class Person < Neo4j::Rails::Model
property :email, :index => :exact, :unique => true
property :name
end
# Either create a new person if there is no person with this email or return a person with this email.
node = Person.get_or_create(:name => 'foo', :email => 'email')
The outgoing
method from the example above does not return a relationship object since it allows to chain several nodes with the << operator (creating several relationship in one line).
If you want to set properties on the relationship it’s more convinient to create it with the Neo4j::Rails::Relationship
# create a relationship with one property
rel = Neo4j::Rails::Relationship.new(:type, n1, n2, :since => 1942)
# add another property on the relationship
rel[:foo] = "bar"
# Don't forget to save it
rel.save
# or create and save it in one go
rel = Neo4j::Rails::Relationship.create(:type, n1, n2, :since => 1942, :foo => 'bar')
TIP: You can of course also subclass the Neo4j::Rails::Relationship
class just like for Neo4j::Rails::Model
class to specify domain specific behavour (e.g. validations, callbacks, business logic etc.)
The has_n and has_one class methods can generate some convenience method for creating and traversing relationships and nodes.
Validation will only be performed on each nested node if the validates_associated
is specified, see below.
class Person << Neo4j::Rails::Model
has_n(:friends)
end
p1 = Person.new # or Person.create
p2 = Person.new
p1.friends << p2
p1.save # => true
Relationship of same class is assumed by default. For relationships between different classes, see Mapping nodes/relationships to Ruby classes
Notice that you can combine using friends
and the outgoing
/ incoming
methods.
These methods may all return both saved and unsaved nodes.
Example:
a.friends << b
a.outgoing(:friends).first # => nil
a.save
a.friends << c
d.incoming(:friends) << a
a.outgoing(:friends).to_a # =>[b,c,d]
TIP: Use ModelClass.relationship
when specifying relationship name. Instead of the example above write a.outgoing(Person.friends)
. The reason is that the relationship is prefixed if it is specified with a to
node. Example Person.has_n(:friends).to(Person)
If you declare which node class a has_n or has_one is then you can use the build and create method on the relationship accessor. Example
Just like Active Record you can create relationship like this:
class Person < Neo4j::Rails::Model
has_n(:friends).to("Person")
end
a.friends.build(property_hash)
a.friends.create(property_hash)
For all generated has_n
and has_one
methods see, Neo4j::Rails::HasN::ClassMethods
Notice You must declare which node class the relationship points to with to
, as shown above.
Neo4j.rb supports accepts_nested_attributes_for which can be used to create relationship between nodes.
The following configuration option are available
-
:allow_destroy
If true, destroys any members from the attributes hash with a _destroy key and a value that evaluates to true (eg. 1, ‘1’, true, or ‘true’). This option is off by default. -
:reject_if
Allows you to specify a Proc or a Symbol pointing to a method that checks whether a record should be built for a certain attribute hash. The hash is passed to the supplied Proc or the method and it should return either true or false. When no :reject_if is specified, a record will be built for all attribute hashes that do not have a destroy value that evaluates to true. Passing :allblank instead of a Proc will create a proc that will reject a record where all the attributes are blank.
When using the accepts_nested_attributes_for
class method you must specify which class the relationship correspond to
by using the to
method in has_one
or has_n
.
Example
class Member < Neo4j::Rails::Model
has_n(:posts).to(Post)
has_one(:avatar).to(Avator)
accepts_nested_attributes_for :avatar, :allow_destroy => true
accepts_nested_attributes_for :posts, :reject_if => proc { |attributes| attributes[:title].blank? }
# when creating, pass in: {:avatar_attributes => {:key => 'value'} }
end
Validation of relationships and nodes for the friends relationship above will always be performed.
If a related nodes or relationship is not valid then an exception will be raised.
The destroy and delete method works like the Active Record methods.
rel = p1.rels(:friends).find{|rel| rel.end_node == p3}
rel.destroy
p1.friends.find(p2).delete
You can also delete the relationship object like this.
p1.friends.delete(p2)
You can destroy and delete all relationship in one go (just like Active Record).
p1.friends.destroy_all
To destroy all relationships:
p1.rels.destroy_all
p1.rels(:friends).delete_all # no callbacks, and only the friends relationships
actor = Actor.create
actor.acted_in << movie1
actor.outgoing(:acted_in) << movie2
actor.outgoing(:acted_in) # only include movie2
actor.outgoing(Actor.acted_in) # only include movie1
TIP: By not specifying which class the relationship is associated to (using the @to@ method above) gives you more freedom. If you instead just declared @Actor.has_n(:acted_in)@ then an actor can have an acted_in relationship to different classes. Example @an_actor.acted_in << Neo4j::Rails::Model.new() << Thingy.create.
h3. Timestamps
If a @Neo4j::Rails::Model@ or a @Neo4j::Rails::Relationship@ class (or subclass) has the property @updated_at@ or @created_at@ then
it will be timestamped. This is all that is required.
```ruby
class Role < Neo4j::Rails::Relationship
property :updated_at
property :created_at
end
That’s all you need to do. If you want to disable this behaviour check the configuration below.
For multitenancy support check this
All write operations requires a transaction. Read operations like find,load or read properties does not require transactions.
The Neo4j::Rails::Model and Neo4j::Rails::Relationship classes does automatically create transaction if needed. If you need to write several operations in one operation use Neo4j::Rails::Transaction
. You will also get better performance using a single transaction instead of several small transactions.
This class can be used as a filter in order to wrap methods in one transactions.
Example:
class UsersController < ApplicationController
around_filter Neo4j::Rails::Transaction, :only => [:create]
The Neo4j::Rails::Transaction
class can also be used to access the current running transaction in order
to signal for a rollback.
Example:
class UsersController < ApplicationController
around_filter Neo4j::Rails::Transaction, :only => [:create, :update]
def update
#.. create, update delete some nodes/relationships
#.. something when wrong, rollback everyting
Neo4j::Rails::Transaction.current.fail
end
Notice that you can also use the Model.transaction
method to wrap a block of code in a transaction.
Example:
class UsersController < ApplicationController
def update
Users.transaction do |tx|
#.. create, update delete some nodes/relationships
#.. something when wrong, rollback everyting
tx.fail
end
end
WARNING: Much of the information in this wiki is out of date. We are in the process of moving things to readthedocs
- Project Introduction
- Neo4j::ActiveNode
- Neo4j::ActiveRel
- Search and Scope
- Validation, Uniqueness, and Case Sensitivity
- Indexing VS Legacy Indexing
- Optimized Methods
- Inheritance
- Core: Nodes & Rels
- Introduction
- Persistence
- Find : Lucene
- Relationships
- Third Party Gems & extensions
- Scaffolding & Generators
- HA Cluster