Nested resource wont create data, rollback transaction right after begin transaction - ruby-on-rails

My problem is that a tag wont be created which is nested in posts.
I have Post which have tags nested in them. Like this
resources :posts do
resources :tags, :only => [:new, :create, :destroy]
end
In my tags controller i have this
class TagsController < ApplicationController
before_filter :authenticate_user!
def new
#post = Post.find(params[:post_id])
#tag = Tag.new
end
def create
#post = Post.find(params[:post_id])
#tag = #post.tags.build(params[:tags])
if #tag.save
flash[:notice] = "Tag created"
redirect_to #tag.post
else
flash[:error] = "Could not add tag at this time"
redirect_to #tag.post
end
end
end
new.html.erb
<%= form_for [#post, #tag] do |f| %>
<% if #tag.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#tag.errors.count, "error") %> prohibited this tag from being saved:</h2>
<ul>
<% #tag.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.text_field :tagable_type, :placeholder => "Type" %>
</div>
<div class="field">
<%= f.text_field :tagable_id, :placeholder => "Id" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Tag model
class Tag < ActiveRecord::Base
attr_accessible :post_id, :user_id, :tagable_type, :tagable_id
validates :post_id, presence: true
belongs_to :tagable, :polymorphic => true
belongs_to :post
belongs_to :user
end
Post model
class Post < ActiveRecord::Base
attr_accessible :body, :link, :thumbnail, :title, :user_id, :youtube, :youtube_id, :website_name, :image_field
default_scope order: 'posts.active DESC'
has_many :tags, :dependent => :destroy
has_many :comments, :as => :commentable, :dependent => :destroy
belongs_to :user
end
UPDATE:
Now i can create a tag but the tagable_type and tagable_id fields are not being created for some reaseon
Started POST "/posts/18/tags" for 127.0.0.1 at 2013-06-26 15:54:14 +0200
Processing by TagsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gwpTs0Qqcrre4tH974RrfpaENGZKtSbkJx2U0H67AcM=", "tag"=>{"tagable_type"=>"Player", "tagable_id"=>"2"}, "commit"=>"Create Tag", "post_id"=>"18"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? ORDER BY posts.active DESC LIMIT 1 [["id", "18"]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "tags" ("created_at", "post_id", "tagable_id", "tagable_type", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?) [["created_at", Wed, 26 Jun 2013 13:54:14 UTC +00:00], ["post_id", 18], ["tagable_id", nil], ["tagable_type", nil], ["updated_at", Wed, 26 Jun 2013 13:54:14 UTC +00:00], ["user_id", 1]]
(6.9ms) commit transaction
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = 18 ORDER BY posts.active DESC LIMIT 1
Redirected to http://localhost:3000/posts/18
Completed 302 Found in 15ms (ActiveRecord: 7.9ms)

There is a typo in the create() action of your TagsController:
#tag = #post.tags.build(params[:tags])
The hash used to create the tag should be params[:tag], not params[:tags].

Related

Creating association with existing model using has_many :through

I'd like users to be able to create a User System with multiple existing Parts. That it. Currently when I edit or create a user system with a part select I get.
Processing by UserSystemsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"LgudsjWoAROXi0DGpUaH0ie2GNAuooRGtsPN+fOg+Gtev6Q6QmJC4dYIwFW9evaBOa0TUWotrQec1o1ROCbwFQ==", "user_system"=>{"name"=>"adfa"}, "parts_user_systems"=>{"part_id"=>["", "2", "3"]}, "button"=>""}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 101]]
(0.1ms) BEGIN
SQL (0.6ms) INSERT INTO "user_systems" ("name", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "adfa"], ["user_id", 101], ["created_at", "2015-07-10 17:10:39.564555"], ["updated_at", "2015-07-10 17:10:39.564555"]]
(0.2ms) COMMIT
Nothing get's submitted to the join table.
class UserSystem < ActiveRecord::Base
has_many :parts_user_systems, foreign_key: "part_id"
has_many :parts, through: :parts_user_systems, foreign_key: "part_id"
end
class Part < ActiveRecord::Base
has_many :parts_user_systems
has_many :user_systems, through: :parts_user_systems
end
class PartsUserSystem < ActiveRecord::Base
belongs_to :part
belongs_to :user_system
end
class UserSystemsController < ApplicationController
def user_system_params
params.require(:user_system).permit(:name, :user_id, part_ids: [:ids])
end
end
_form.html.erb
<%= form_for(#user_system) do |f| %>
<div class="field">
<%= f.label :part_id, "Part " %><br/>
<%= collection_select :parts_user_systems, :part_id, Part.all, :id, :name, {:selected => 1}, {:multiple => true} %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
</div>
<% end %>
show.html.erb
<%= #user_system.parts.each do |part| %>
<li><%= part.name%> by by <%= part.parts_user_system%></li></li>
<% end %>

How to change development?

I get some error to insert following_id, then i checked the development.log:
This is my false: follower_id = nil
[1m[35mUser Load (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 9]]
[1m[36mUser Load (1.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1[0m [["id", "11"]]
[1m[36mSQL (3.0ms)[0m [1mINSERT INTO "relations" ("created_at", "follower_id", "following_id", "updated_at") VALUES (?, ?, ?, ?)[0m [["created_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00], ["follower_id", nil], ["following_id", 11], ["updated_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00]]
I wan it to become: follower_id = 9, change between line 1 and 2
[1m[36mUser Load (0.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1[0m [["id", "9"]]
[1m[35mUser Load (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "11"]]
[1m[36mSQL (3.0ms)[0m [1mINSERT INTO "relations" ("created_at", "follower_id", "following_id", "updated_at") VALUES (?, ?, ?, ?)[0m [["created_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00], ["follower_id", 9], ["following_id", 11], ["updated_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00]]`
So,How can i change it to be true???Some thing wrong with my code??Please help me!
*This is my User model
class User < ActiveRecord::Base
attr_accessible :pass, :username
# Who am I following?
has_many :relations, :foreign_key => :follower_id
has_many :following, :through => :relations
# Who am I followed by?
has_many :relations, :class_name => "Relation", :foreign_key => :following_id
has_many :followers, :through => :relations
validates :username, :pass, :presence => true
validates :username, :pass, :length => { :minimum => 4 }
validates :username, :uniqueness => true
*the relation model
class Relation < ActiveRecord::Base
belongs_to :follower, :class_name => "User"
belongs_to :following, :class_name => "User"
end
*relation controller
class RelationController < ApplicationController
def create
follow = User.find(params[:relation][:following_id])
#current_user.following << follow
redirect_to follow
end
*my ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include WelcomeHelper
before_filter :set_current_user
private
def set_current_user
#current_user = User.find(session[:user_id]) if session[:user_id]
end
end
*my action view
<h2><%= #user.username%><br /></h2>
<%= #user.pass%><br />
<% if #current_user && #current_user != #user %>
<% if #current_user.following.include?(#user) %>
<%= link_to "Unfollow",
relation_path(#current_user.relation_for(#user)),
:method => :delete %>
<% else %>
<%= form_for #relation do |f| %>
<%= f.hidden_field :following_id, :value => #user.id %>
<%= f.submit "Follow" %>
<% end %>
<% end %>
<% end %>
<br>
<ul>
<% #user.following.each do |u| %>
<li><%= link_to u.username, u %></li>
<% end %>
</ul>
Followed By
<ul>
<% #user.followers.each do |u| %>
<li><%= link_to u.username, u %></li>
<% end %>
</ul>
This is my action to insert following_id
def create
follow = User.find(params[:relation][:following_id])
#current_user.following << follow
redirect_to follow
end
and my following_id has been sent
{"utf8"=>"✓",
"authenticity_token"=>"DIY42kGR9fZ54Pub+CDMuNNaHZ0aFnzSiWrkOFRBsdE=",
"relation"=>{"following_id"=>"11"},
"commit"=>"Follow"}

Rails4: Why insert a new record when delete a image uploaded with carrierwave?

When I delete a image which was uploaded using carrierwave, a new record is inserted at the same time.
How can I avoid inserting a new record?
article has many photo.
sqlite> .schema photos
CREATE TABLE "photos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "articl_id" integer, "image" varchar(255), "created_at" datetime, "updated_at" datetim);
The id 93 and 94 exist before deleting photo.
sqlite> select * from photos;
93|27|DSCN0722_070.JPG|2014-09-07 01:59:03.320092|2014-09-07 01:59:03.320092
94|27|DSCN0725_070.JPG|2014-09-07 01:59:03.332093|2014-09-07 01:59:03.332093
When I checked check box to delete id=93 and submitted, id=93 is deleted I expected but a new record id=95 is inserted with no image, I'm not sure.
sqlite> select * from photos;
94|27|DSCN0725_070.JPG|2014-09-07 01:59:03.332093|2014-09-07
95|27||2014-09-07 02:01:58.634119|2014-09-07 02:01:58.634119
If there are 3 records, it works (a new record isn't inserted).
But there are 2 records like above, it occurs.
Thanks in advance.
log/development.log
.
.
Started PATCH "/articles/27" for 127.0.0.1 at 2014-09-07 11:01:58 +0900
Processing by ArticlesController#update as HTML
Parameters: {"utf8"=>"笨・, "authenticity_token"=>"xxx=", "article"=>{"category_id"=>"1379", "photos_attributes"=>{"0"=>{"article_id"=>"27", "_destroy"=>"1", "id"=>"93"}, "1"=>{"article_id"=>"27", "_destroy"=>"0", "id"=>"94"}, "2"=>{"article_id"=>"27"}}, "content"=>"test"}, "commit"=>"譖エ譁ー縺吶k", "id"=>"27"}
[1m[35mUser Load (1.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'xxxx' LIMIT 1
[1m[36mArticle Load (0.0ms)[0m [1mSELECT "articles".* FROM "articles" WHERE "articles"."user_id" = ? AND "articles"."id" = 27 ORDER BY created_at DESC LIMIT 1[0m [["user_id", 1]]
[1m[35mArticle Load (0.0ms)[0m SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? ORDER BY created_at DESC LIMIT 1 [["id", "27"]]
[1m[36m (0.0ms)[0m [1mbegin transaction[0m
[1m[35mPhoto Load (1.0ms)[0m SELECT "photos".* FROM "photos" WHERE "photos"."article_id" = ? AND "photos"."id" IN (93, 94) [["article_id", 27]]
[1m[36m (0.0ms)[0m [1mSELECT COUNT(*) FROM "photos" WHERE "photos"."article_id" = ?[0m [["article_id", 27]]
#Delete id=93
[1m[35mSQL (0.0ms)[0m DELETE FROM "photos" WHERE "photos"."id" = ? [["id", 93]]
#Why new record is inserted?
[1m[36mSQL (0.0ms)[0m [1mINSERT INTO "photos" ("article_id", "created_at", "updated_at") VALUES (?, ?, ?)[0m [["article_id", 27], ["created_at", Sun, 07 Sep 2014 02:01:58 UTC +00:00], ["updated_at", Sun, 07 Sep 2014 02:01:58 UTC +00:00]]
[1m[35m (5.0ms)[0m commit transaction
Redirected to http://localhost:3000/users/1
Completed 302 Found in 48ms (ActiveRecord: 7.0ms)
\models\article.rb
# encoding: utf-8
class Article < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos, reject_if: :all_blank, allow_destroy: true
default_scope -> { order('created_at DESC') }
validates :content, presence: true, length: { maximum: 140 }
validates :user_id, presence: true
validates :category_id, presence: true
validate :check_for_at_least_image
def build_images
(3 - self.photos.size).times {self.photos.build}
end
def check_for_at_least_image
errors.add(:image, "select...") if self.photos.size <= 0
end
end
\models\photo.rb
class Photo < ActiveRecord::Base
belongs_to :article
mount_uploader :image, ImageUploader
end
\view\articles\edit.html.erb
<div class="row">
<div class="span8">
<%= render 'shared/article_form' %>
</div>
</div>
\view\shared\ _article_form.html.erb
<%= form_for(#article) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.hidden_field :category_id %>
<%= f.fields_for :photos do |p| %>
<%= p.hidden_field :article_id %>
<div class="photo">
<% if p.object.image and p.object.image.file %>
<%= image_tag p.object.image.thumb.url %>
<p>article:<%= #article.id %></p>
<p>photo:<%= p.object.id %></p>
<%= p.hidden_field :image_cache if p.object.image_cache %>
<label><%= p.check_box :_destroy %>delete</label>
<% end %>
<%= p.file_field :image %>
</div>
<% end %>
<%= f.text_area :content, placeholder: "Enter content..." %>
</div>
<%= f.submit class: "btn btn-large btn-primary" %>
<% end %>
\controllers\articles_controller.rb
class ArticlesController < ApplicationController
before_action :signed_in_user, only: [:create, :destroy]
before_action :correct_user, only: [:update, :destroy]
.
.
def new
#article = Article.new
#category = Category.find(params[:category])
#article.category_id = #category.id
3.times { #article.photos.build }
end
def create
#article = current_user.articles.build(article_params)
if #article.save
flash[:success] = "article created!"
redirect_to current_user #root_url
else
#article.build_images
render 'new'
end
end
.
.
def edit
#article = Article.find(params[:id])
#article.build_images
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to current_user
else
render 'edit'
end
end
def destroy
#article.destroy
redirect_to root_url
end
private
def article_params
params.require(:article).permit(:content, :category_id, photos_attributes: [:id, :article_id, :image, :image_cache, :_destroy])
end
.
.
end
If you look at your logs attributes for other image are still passed to the update action when you are deleting a image
"article"=>{"category_id"=>"1379", "photos_attributes"=>{"0"=>{"article_id"=>"27", "_destroy"=>"1", "id"=>"93"}, "1"=>{"article_id"=>"27", "_destroy"=>"0", "id"=>"94"}, "2"=>{"article_id"=>"27"}}, "content"=>"test"}, "commit"=>"譖エ譁ー縺吶k", "id"=>"27"}
FIX
You have two options:
a. Don't build a new image in edit action:.
You are building a new image in your edit action which is then passed on to your update method when you submit your form so you can remove this line in edit action and fix your issue
#article.build_images
b. Use a Proc instead of blank_all:
If you look at your code you have
accepts_nested_attributes_for :photos, reject_if: :all_blank, allow_destroy: true
You are using reject_if: :all_blank instead of a Proc, if you look at docs, it says
Passing :all_blank instead of a Proc will create a proc that will reject a record where all the attributes are blank excluding any value for _destroy.
and in your case attributes are still being passed for other image so it's creating a new image for you. You can use a Proc to eliminate this:
accepts_nested_attributes_for :photos, reject_if: proc { |attributes| attributes['image'].blank? }, allow_destroy: true
You are building images for three times always in your article model. When you try to delete image from two images there is also a blank object present for photo that is created by build and when you submit in update action this part #article.update(article_params) add a blank object and also delete an object for photo table. That's why you are getting this issue. Check your params before updating record for photo will solve your issue.

Rails and ancestry - form submits 'parent_id' empty

I've followed Railscast episode #262 tutorial on ancestry. But when I submit my form, the rails server log says that parent_id is empty:
rails server log:
Started POST "/posts/1/comments" for 127.0.0.1 at 2013-09-26 16:14:59 +0200
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"9+9U/etsazbrJxwWah/eRD9v3fKBnjpy+y5s+g7N/Bw=", "comment"=>{"parent_id"=>"", "author"=>"some name", "author_email"=>"mail#domain.com", "author_url"=>"", "content"=>"banane"}, "commit"=>"Post Comment", "post_id"=>"1"}
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1 [["id", "1"]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "comments" ("author", "author_email", "author_url", "content", "created_at", "post_id", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["author", "some name"], ["author_email", "mail#domain.com"], ["author_url", ""], ["content", "banane"], ["created_at", Thu, 26 Sep 2013 14:14:59 UTC +00:00], ["post_id", 1], ["updated_at", Thu, 26 Sep 2013 14:14:59 UTC +00:00]]
(38.6ms) commit transaction
(0.1ms) begin transaction
(0.1ms) commit transaction
Redirected to http://0.0.0.0:3000/posts/1
Completed 302 Found in 49ms (ActiveRecord: 39.4ms)
comments_controller.rb:
def new
#comment = Comment.new
#comment.parent_id=params[:parent_id]
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:author, :author_email, :author_url, :content, :parent_id))
respond_to do |format|
if #comment.save
stuff
else
other stuff
end
end
end
def comment_params
params.require(:comment).permit(...some stuff..., :parent_id)
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :post
has_ancestry
end
post.rb:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
accepts_nested_attributes_for :comments
end
views/posts/show.html.erb:
<% #post.comments.each do |comment| %>
<%= show some stuff %>
<%= link_to (post_path(:anchor => "respond", :parent_id => comment)) do%>
<%= "Reply"%>
<% end %>
<% end %>
<%= render 'comments/comment_form'%>
_comment_form.html.erb:
<%= form_for [#post, #post.comments.build], html: { :id => "commentform"} do |f| %>
<%= f.hidden_field :parent_id %>
<%= some fields %>
<%= f.submit "Post Comment"%>
Rails debug info:
--- !ruby/hash:ActionController::Parameters
parent_id: '17'
action: show
controller: posts
id: '1'
I guess somethings wrong with my create method in the CommentsController, but I can't figure out what's missing. So, I got this working. I was submitting the form from my posts/show view, so I had to call #comment = Comment.new(:parent_id => params[:parent_id]) in the show action of the post-controller as well.
If you are using Rails >3.0.0 try this in your comments controller:
#comment = Comment.new
#comment.parent_id=params[:parent_id]
instead of
#comment = Comment.new(:parent_id => params[:parent_id])
Add :parent_id to comment_params in the comments controller.

Nested form not saving in rails 3.1

Noob question, I'm sure, but I can't seem to find my mistake. SymptomSets are saving w/ the proper user_id, but the nested symptoms disappear. Note that the user model structure is identical to that in the Rails Tutorial (save that it has_many :symptom_sets)
Models:
class SymptomSet < ActiveRecord::Base
attr_accessible :symptoms, :symptoms_attributes
belongs_to :user
has_many :symptoms, :dependent => :destroy
accepts_nested_attributes_for :symptoms, allow_destroy: true
end
class Symptom < ActiveRecord::Base
attr_accessible :name, :duration, :symptom_set_id
belongs_to :symptom_set
end
Controller:
class SymptomSetsController < ApplicationController
before_filter :signed_in_user, only: [:create, :new]
def new
#symptom_set = SymptomSet.new
3.times do
symptom = #symptom_set.symptoms.build
end
end
def create
#symptom_set = current_user.symptom_sets.build(params[:symptom_sets])
if #symptom_set.save
flash[:success] = "Symptoms submitted!"
redirect_to root_url
else
render 'static_pages/home'
end
end
And the View:
<%= simple_form_for #symptom_set, :html => { :class => 'form-inline' } do |f| %>
<%= f.fields_for :symptoms do |builder| %>
<%= render 'symptom_fields', f: builder %>
<% end %>
<div class="actions"><%= f.submit %></div>
<% end %>
And the partial:
<%= f.input :name,
:collection=> ["Cough", "Fever", "Headache", "Lethargy"],
label: "Symptom",
prompt: "Select a symptom",
:input_html => { :class => "span3" }%>
<%= f.input :duration,
:collection => 1..14,
label: "Duration",
prompt: "How many days?" %>
finally, the rails server console outputs the following:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"s7ksuk40M2r76Nq4PGEEpTpkCECxFniP4TtpfSHszQk=", "symptom_set"=>{"symptoms_attributes"=>{"0"=>{"name"=>"Cough", "_destroy"=>"false", "duration"=>"2"}, "1
"=>{"name"=>"Fever", "_destroy"=>"false", "duration"=>"2"}, "2"=>{"name"=>"", "_destroy"=>"1", "duration"=>""}}}, "commit"=>"Create Symptom set"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" ='OH6_nuvySNjd6AbTuDunsw' LIMIT 1
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO "symptom_sets" ("created_at", "updated_at", "user_id") VALUES ($1, $2, $3)
RETURNING "id" [["created_at", Tue, 05 Feb 2013 21:12:07 UTC +00:00], ["updated_at", Tue, 05 Feb 20
13 21:12:07 UTC +00:00], ["user_id", 1]]
(1.1ms) COMMIT
I'd try changing:
#symptom_set = current_user.symptom_sets.build(params[:symptom_sets])
to:
#symptom_set = current_user.symptom_sets.new(params[:symptom_sets])
I don't know if build would work there.
And also checking the params on the terminal log if it is called symptom_sets and if it's sending the parameters of nested form attributes.
EDIT:
I Really think your param's name would be symptom_set in singular. check that.

Resources