Skip to content

Instantly share code, notes, and snippets.

@farmanp
Created December 29, 2016 19:46
Show Gist options
  • Save farmanp/945df490b79962aeee71690bf66430ca to your computer and use it in GitHub Desktop.
Save farmanp/945df490b79962aeee71690bf66430ca to your computer and use it in GitHub Desktop.
Undefined properties from and to
<%= form_for([@post, @comment]) do |f| %>
<% if @comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% @comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
def create
@comment = Comment.new(comment_params)
respond_to do |format|
if @comment.save
# using the ActiveRel model to create the relationship
# callbacks, validations would run
# it will be timestamped as any other model since a :created_at property is present
Post.create(from_node: @post, to_node: @comment)
# alternatives
# @post.comments << @comment
# or
# create a relationship with a created property between post and comment
# @post.comments.create(@comment, :created => Time.now.to_i)
format.html { redirect_to @post, notice: 'Comment was successfully created.' }
format.json { render action: 'show', status: :created, location: @comment }
else
format.html { render action: 'new' }
format.json { render json: @comment.errors, status: :unprocessable_entity }
end
end
end
@subvertallchris
Copy link

Since you're creating the comment, immediately creating the rel, and you don't want anything to save if one piece fails, you can do this easier, faster, and safer by using an ActiveRel class to handle the relationship between the Post and Comment. If we pretend it is called HasComment, you'd do this:

@comment = Comment.new(comment_params)
rel = HasComment.new(@post, @comment)
respond_to do |format|
  if rel.save
    # the rest is the same
  end
end

HasComment will recognize that @comment is unpersisted. It will create the node and rel in a single Cypher query. If a validation fails at any point, it will append errors; if it is successful, it will modify the state of your @comment object so it will act as persisted. Since it happened in a single query, if an error was encountered (maybe the Post was deleted in the ms after Comment creation...) it will fail the entire action.

The only thing to double check is whether validation errors for @comment will be added to that instance or rel. They should be on @comment (in other words, a failure of rel.save should also change @comment.errors) but I am not entirely sure, it has been many months since I last worked with this. If not, you can at rel.errors and you'll see the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment