Is an update to the neo4j-rails-example coming?

15 views
Skip to first unread message

Max De Marzi

unread,
Jan 19, 2010, 10:02:44 PM1/19/10
to neo4jrb
Finally able to get back to trying this out, but ran into a problem
right away with the neo4j-rails-example.

Processing ActorsController#index (for 24.136.9.221 at 2010-01-20
02:54:48) [GET]

Jan 20, 2010 2:54:48 AM sun.reflect.GeneratedMethodAccessor1 invoke
INFO:
NoMethodError (undefined method `all' for Actor:Class):
app/controllers/actors_controller.rb:7:in `index'
app/controllers/actors_controller.rb:63:in `neo_tx'
:1

Since the refactor is there a new way to write the index action?

def index
@actors = Actor.all.nodes
end

Thanks,
Max

Max De Marzi Jr.

unread,
Jan 19, 2010, 10:16:49 PM1/19/10
to neo4jrb
Nevermind...somewhere along the lines I must have deleted

require 'neo4j/extensions/reindexer' 

from the environment.rb file

Thanks,
Max

Max De Marzi Jr.

unread,
Jan 24, 2010, 3:39:25 PM1/24/10
to neo4jrb
Sorry to keep talking to myself, but...

In the neo4j-rails example, I could not get Related Actors to show up in /app/views/movies/show.html.erb until I changed from

<%  @movie.rels.incoming(:acted_in).each do |relationship| %>

to

<%  @movie.rels.incoming("Movie#acted_in").each do |relationship| %>


Is this how it's supposed to work from now on? With the class type # relationship type or is there a better way?

Thanks,
Max

Andreas Ronge

unread,
Jan 25, 2010, 3:27:46 AM1/25/10
to neo...@googlegroups.com
Hi

There are two ways of working with relationships:
* undeclared - using the rels method
* declared - using the has_n, has_one, has_list methods

The problem is when you want to use the rels method on declared
relationships - then you might have to prefix the
relationships with the classname, as you described.

The reason for this behaviour can be found here:
http://neo4j.lighthouseapp.com/projects/15548/tickets/92-has_onefrom-using-the-wrong-has_nto

Instead of using the @movie.rels.incoming("Movie#acted_in") you should
use the declared actors method which is
defined in the example: the app/models/movie.rb

class Movie
include Neo4j::NodeMixin
property :title
property :year

# defines a method for traversing incoming acted_in relationships from Actor
has_n(:actors).from(Actor, :acted_in)
end

So try to change
@movie.rels.incoming("Movie#acted_in")
to
@movie.actors

I would be great if you could fix that in the example so that I can
pull from you.

/Andreas

> --
> You received this message because you are subscribed to the Google Groups
> "neo4jrb" group.
> To post to this group, send email to neo...@googlegroups.com.
> To unsubscribe from this group, send email to
> neo4jrb+u...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/neo4jrb?hl=en.
>

Max De Marzi Jr.

unread,
Jan 25, 2010, 11:37:04 AM1/25/10
to neo...@googlegroups.com
If I switch it to @movie.actors we are getting not the relationships but the end nodes of those relationships. Right?

So the next statement in the view breaks:
<%  @movie.actors.each do |relationship| %>

<%= link_to 'Unlink', {:action => "unlink", :id => relationship.end_node.neo_id, :actor_id => relationship.start_node.neo_id, :rel_id => relationship.neo_id} %>

We can refactor this to:

<%= link_to 'Unlink', {:action => "unlink", :id => @movie.neo_id, :actor_id => relationship.neo_id, :rel_id => ?????} %>

but where do I get the relationship.neo_id if we are returning actors?

Thanks,
Max

Andreas Ronge

unread,
Jan 25, 2010, 2:25:43 PM1/25/10
to neo...@googlegroups.com
Yes, you are right.
I have to think of a way to access the declared relationships as well
as nodes - any suggestions ?

Maybe
@movies.actors.rels ?
or should the rels method understand declared relationships as well ?

What do you think ?

Max De Marzi Jr.

unread,
Jan 25, 2010, 5:33:58 PM1/25/10
to neo...@googlegroups.com
Well... @movies.actors.rels could mean all Relationships of the nodes returned by actors.

So why not stick with the named Relationship of Role?

In the Movie model, if we change 
has_n(:actors).from(Actor, :acted_in)

to
has_n(:actors).from(Actor, :acted_in).relationship(Role, :roles)

then it would make sense that
@movies.roles #gives me roles
@movies.actors #gives me actors

Anyone else want to chime in?

Stephen Cremin

unread,
Jan 25, 2010, 9:49:59 PM1/25/10
to neo...@googlegroups.com
I think Max is right that @movies.actors.rels is confusing.

But I can see that there are going to be a naming burden with his solution in less simple examples. We're already naming objects at different ends of the relationship, and now there would be a need to also name those relationships. In my own code, for example, if I have Role (or rather CastingEvent) as a node rather than as a relationship for various reasons.

How about:
@movies.actors  #gives me actors
@movies.actors_rels #gives me members of a has_n relationships between Movie and Actor

And if, say, every Actor class has_one agent:
@movies.actors.agent #gives me a set of all agent nodes related to actors
@movies.actors.agent_rel # gives me a set of all relationships to agents from actors related to movie

Note (1) difference between "_rel" (has_one) and "_rels" (has_many) unless that's thinking too much and (2) that one can't name nodes with a "_rel" suffix which probably encourages better naming practises.

Stephen




2010/1/26 Max De Marzi Jr. <maxde...@gmail.com>

Andreas Ronge

unread,
Jan 26, 2010, 3:41:07 AM1/26/10
to neo...@googlegroups.com
Thanks for great input !
I like Max version since it's easy to read and understand which
relationships is what.
But I also agree with Stephen with its problem.

How about
@movies.actors.roles
which is available when you declare it with
has_n(:actors).from(Actor, :acted_in).relationship(Role, :roles)
Maybe that's a bit too much magic and it's not clear that roles gives
you relationship object instead of nodes.

It's also possible to let the actors method take an argument (a symbol
or a hash), like:
@movie.actors(:rels).each

I think I prefer Stephens version, it is also easier to implement.

What do you think ?

I have to do some more thinking.

Would also be cool to allow navigation in several relationships like
@movie.actors.agent.friends or
@movie.actors{salary > 100000).agent{:name == 'james'}.movies.each { ...}
or with rels
@movies.actors_rels{role == 'hero'}.agent.each ...

/Andreas

Stephen Cremin

unread,
Jan 26, 2010, 1:37:33 PM1/26/10
to neo...@googlegroups.com
Andreas, I love the idea of:
@movie.actors{salary > 100000).agent{:name == 'james'}.movies.each { ...}
@movies.actors_rels{role == 'hero'}.agent.each ...

But for the latter, perhaps it would make more logical sense (if more verbose) to write:
@movies.actors_rels{role == 'hero'}.actors.agent.each ...

Which would also permit mixing and matching node and relationship qualifiers:
@movies.actors_rels{role == 'hero'}.actors{name == 'mcclane'}.agent_rel{:representation == "north america}.agent.each ...

But I can't help feeling there's an even better way of representing that, but I need to sleep on it!

I recently read an analysis of relational database practice that argued that eventually every one-to-one and one-to-many relationship ends up as a many-to-many relationship as the real world encroaches. While I think "has_one" (with "=" instead of "<<" for assignment) is expressive I would be against dropping it and only permitting "has_many" and "has_list". 

In the same vein (and back on topic!), perhaps we should drop "..._rel" and only use "..._rels" because (a) it would reduce difficult-to-spot typing errors; (b) often with "_rel", we're pehaps confusingly returning multiple results because the qualifier is operating on a set, even if each member of the set only return one relationship by itself; and (c) because eventually that "has_one" is going to become a "has_many" anyway and we may as well localize those changes now!

(Even if an actor can logically only have one date-of-birth, you're going to want to track multiple dates-of-birth to represent that different sources disagree on that date. You may want to add a relationship to that source - or sources that agree - on the actual nodes representing those date-of-births. The beauty of a graph database is that one can model with this richness. We just need an expressive enough language to navigate it.)

Stephen



2010/1/26 Andreas Ronge <andrea...@jayway.se>

Max De Marzi Jr.

unread,
Jan 27, 2010, 1:08:07 AM1/27/10
to neo...@googlegroups.com

The initial problem was with making this:
@movie.rels.incoming("Movie#acted_in")

feel cleaner.  How about @movie.rels.acted_in  ?

going with @movies.actors_rels feels backward to me because we are specifying the end node first and then specifying the relationship afterwards.

@movies.actors_rels{role == 'hero'}.actors{name == 'mcclane'}.agent_rel{:representation == "north america}.agent.each ... becomes
@movies.rels.acted_in{role == 'hero'}.actors{name == 'mcclane'}.rel.represented_by{:representation == "north america}.agent.each ...

Stephen Cremin

unread,
Jan 27, 2010, 1:35:36 AM1/27/10
to neo...@googlegroups.com
Thanks Max.

Just thinking out loud, but how does @movies.rels_acted_in sound to you?

And @movies.rels_acted_in.actors as an optional equivelent to @movies.actors if you wanted to qualify the actors with information in the relationship such as @movies.rels_acted_in{kind == "cameo"}.actors?

Thanks for re-grounding the discussion!

Stephen


2010/1/27 Max De Marzi Jr. <maxde...@gmail.com>

Andreas Ronge

unread,
Jan 27, 2010, 6:19:18 AM1/27/10
to neo...@googlegroups.com
Hmm

The actors method is generated by the following line:
has_n(:actors).from(Actor, :acted_in)

I would prefer not using the acted_in for accessing relationships. Why
should the user care about if it is incoming or outgoing from a
different class ?
Also, if the user change the acted_in relationship later it would be
more things to change in his code.
Instead, I would prefer only using the actors method and maybe an
actors_rels method so that the knowledge of direction and relationship
can
be abstracted away.

I would also keep the rels method for only low level undeclared
relationships and the generated method (by has_n)
for navigation in declared relationships.

> going with @movies.actors_rels feels backward to me because we are specifying the end node first and then specifying the relationship afterwards.

But does the user want to know the direction (incoming acted_in) of
the relationship when using declared relationships ?
Is it not enough for the user to know that he wants the relationships
from the actors method ?

What do you think ?

Max De Marzi Jr.

unread,
Jan 27, 2010, 11:38:41 AM1/27/10
to neo...@googlegroups.com
You know, I think I confused myself because :actors is also the name of the Actor node class.

If we do this with Person it does make sense.

  class Person
     include Neo4j::NodeMixin
     has_n :knows  # will generate a knows method for outgoing relationships
     has_n(:known_by).from(Person, :knows)  #  will generate a known_by method for incoming knows relationship
  end
@person.knows      # Nodes from Knows outgoing relationship
@person.knows_rels # Relationships from Knows outgoing relationship
@person.known_by # Nodes from Known_by incoming relationship
@person.known_by_rels # Relationships from Known_by incoming relationship

Yeah, this works.

Andreas Ronge

unread,
Jan 28, 2010, 7:49:53 AM1/28/10
to neo...@googlegroups.com
Thanks for great discussion !
I have added a ticket on this
http://neo4j.lighthouseapp.com/projects/15548-neo4j/tickets/104-access-declaredprefixed-relationships-for-has_n-and-has_one

Anybody tempted to implement this ?

I'm not sure about the _by and _by_rels methods.
Why do we need them ?
By using the has_n and has_one there is no need to know the direction
of relationships, or is it ?
Depending on how knows was declared @person.knows and
@person.knows_rels will give is either incoming or outgoing
nodes/relationships.

Stephen Cremin

unread,
Jan 28, 2010, 1:00:50 PM1/28/10
to neo...@googlegroups.com
Thanks, Andreas. I like the description of the proposed new functionality in the lighthouse ticket.

Stephen

Andreas Ronge

unread,
Jan 30, 2010, 10:04:06 AM1/30/10
to neo...@googlegroups.com
Hi

I have now implemented this feature.
You can now access relationship using both _rels (e.g.
person.friends_rels) and _rel (e.g. person.manager_rel) method.

I implement this feature in the HasN class which means that you can
also access relationships like this:
person.friends.rels
which is the same as person.friends_rels

The only thing missing is now testing and updating the rails example.
@Max: Do you want to fix the rails example ?

I will add another lighthouse ticket on permitting mixing and matching
node and relationship qualifiers
(allow something like @movies.actors_rels{role == 'hero'}.actors{name


== 'mcclane'}.agent_rel{:representation == "north america}.agent.each

...)

/Andreas

jia

unread,
Feb 7, 2010, 3:30:34 AM2/7/10
to neo4jrb
I was trying to implement this feature. I tried to add a function
"condition" in class RelationshipDSL where you can add the property
and value need to be evaluated. I was able to evaluate the condition
and get the end_node for that relationship. I put the result in an
array, but I don't know how I can put the result in some
container(maybe Neo4j::Relationships::HasN?) and then go on to
evaluate the next condition.

The example shows what I did: the property for acted_in which is
named :name is evaluated against :value "name1"; if the condition met,
then the result is collected into some container, and then chained to
the next node.

irb(main):813:0>
actor1.acted_in_rels.condition({:rel_property=>:name,:value=>"name1"})
=> [#<Movie:0x17892d5 @_java_node=#<#<Class:01x1971eb3>:0xeff545
@_wrapper=#<Movie:0x17892d5 ...>>>]
irb(main):814:0>


thanks,
jia

Andreas Ronge

unread,
Feb 7, 2010, 12:11:30 PM2/7/10
to neo...@googlegroups.com
Great.
I think it should be a bit similar to filtering nodes in a a has_n
relationship.
You can now write
actor1.acted_in{name == 'jimmy'}.each
Not sure how much of that code could be reused for filtering relationship
Btw, the block {name == 'jimmy'} is evaluated in the context of the
node, that's why one cane write just: name == 'jimmy'

Will add a lighthouse ticket on this
/Andreas

jia

unread,
Feb 7, 2010, 3:56:54 PM2/7/10
to neo4jrb
Andreas; Thanks for the feedback. Will try to work on it more.

On Feb 7, 11:11 am, Andreas Ronge <andreas.ro...@jayway.se> wrote:
> Great.
> I think it should be a bit similar to filtering nodes in a a has_n
> relationship.
> You can now write
>   actor1.acted_in{name == 'jimmy'}.each
> Not sure how much of that code could be reused for filtering relationship
> Btw, the block  {name == 'jimmy'} is evaluated in the context of the
> node, that's why one cane write just: name == 'jimmy'
>
> Will add a lighthouse ticket on this
> /Andreas
>

Reply all
Reply to author
Forward
0 new messages