I have 3 models:
User: has_many :comments
Video: has_many :comments
Comment: belongs_to :video, :user
videos/show.html.erb
<%= form_for(#comment, :method => :post ) do |f| %>
<%= f.text_area :body %>
<%= f.hidden_field :video_id, :value =>"4" %>
<%= f.submit "submit" %>
<% end %>
comments_controller
def create
#comment = Comment.new(params[:comment].merge(:user_id => current_user.id))
#comment.save
end
How can i check existence of Video before i create a comment?
This should be present as a validation in your Comment model.
class Comment < ActiveRecord::Base
validates_presence_of :video
Related
I GOT TWO PROBLEMS:
-I'm stuck with creating a project which includes nested attributes for :position
-I got it nearly working for editing the project details plus the :position attribute, but the fields_for :assigned_projects ads all the fields for all users who are assigned to the project.
I have 3 Models:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
attr_accessible :name, :controlled, :currency, :creator_id, :assigned_projects
accepts_nested_attributes_for :assigned_projects#, :allow_destroy => true
end
class AssignedProject < ActiveRecord::Base
belongs_to :user, class_name: "User"
belongs_to :project, class_name: "Project"
attr_accessible :project_id, :user_id, :position, :project, :user, :user_attributes
accepts_nested_attributes_for :user
end
Each User can create a Project and is the Projects.creator
Each Project has_many Users through the join model Assigned_Project
Each User can have a different position in the project, so I want to save the :position in the join model AssignedProject.
if a user creates a Project, he should be able to edit the project attributes PLUS the :position attribute of the new join model.
Now the Form field for New.Project and Edit.Project
/project/new.htm.erb
<%= form_for( setup_new_project(#project) ) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :assigned_projects do |ff| %>
<%= ff.label :position %>
<%= ff.text_field :position%>
<% end %>
<%= f.submit "Add Project", class: "" %>
<% end %>
/project/edit.htm.erb
<%= form_for( setup_project(current_project) ) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :assigned_projects do |ff| %>
<%= ff.label :position %>
<%= ff.text_field :position%>
<% end %>
<%= f.submit "Update Project", class: "" %>
<% end %>
And I have the following setup methods as described in this article:
http://www.sitepoint.com/complex-rails-forms-with-nested-attributes/
module FormHelper
def setup_project(project)
project.assigned_projects ||= AssignedProject.new
project
end
def setup_new_project(project)
project.assigned_project = AssignedProject.new
project
end
end
I hope the problem is clear enough.
for creating a new project the current error message is:
undefined method `assigned_project='
15: <%= render 'shared/user_sidebar_menu' %>
16:
17: <div class="span4 offset1">
18: <%= form_for( setup_new_project(#project) ) do |f| %>
19:
20: <%= render 'shared/error_messages', object: f.object %>
21:
UPDATE: added projects_controller.rb
projects_controller.rb
class ProjectsController < ApplicationController
def new
#project = Project.new
end
def create
#project = Project.new(params[:project])
#project.creator = current_user
if #project.save
current_user.assigned_projects.create(project: #project)
redirect_to current_user
else
render 'new'
end
end
end
Update setup_new_project method as below:
def setup_new_project(project)
project.assigned_projects.build ## Updated this line
project
end
Use project.assigned_projects(Notice plural) instead of project.assigned_project(Notice singular WRONG).
User and AssignedProject model are in a 1-M relationship. So, you get dynamic method assigned_projects=(Notice plural), you are getting error as you called assigned_project=(Notice singular) which does not exist.
UPDATE
undefined method each for <AssignedProject:0x007ff7aa55b528>
Use project.assigned_projects.build instead of project.assigned_project = AssignedProject.new.
UPDATE 2
You are approaching this incorrectly. The form helpers are totally not required. All you need to do is update the new and create actions as below:
def new
#project = Project.new
#project.assigned_projects.build
end
and update the form_for in both new and edit view's as below:
<%= form_for(#project) do |f| %>
Can't mass-assign protected attributes: answer. (Using Rails3)
I'm not sure why it's not allowing me to do so as I have my nested attributes accessible.
This is my answer model
class Answer < ActiveRecord::Base
has_many :comments, dependent: :destroy
belongs_to :question
attr_accessible :anonymous, :answer, :commenter, :votes, :comments_attributes
accepts_nested_attributes_for :comments
end
This is my comments model
class Comment < ActiveRecord::Base
belongs_to :answer
attr_accessible :anonymous, :comment, :writer, :votes
end
I'm failing at this form on the view
<%= form_for([#answer, #comment]) do |f| %>
<p>
<%= f.label :comment %>
<%= f.text_area :comment, :cols => "50", :rows => "30"%>
</p>
<p>
<%= f.submit "Submit Comment" %>
</p>
<% end %>
This is my function in my commentsController that is apparently causing the error
def create
#answer = Answer.find(params[:answer_id])
#comment = #answer.comments.new(params[:comment])
#comment.save
redirect_to question_path(#answer)
end
Your view code is not technically right. You need to use fields_for:
<%= form_for([#answer, #comment]) do |f| %>
<p>
<%= f.fields_for :comments do |u| %>
<%= u.label :comment %>
<%= u.text_area :comment, :cols => "50", :rows => "30"%>
<% end %>
</p>
<p>
<%= f.submit "Submit Comment" %>
</p>
<% end %>
you may also need to remove #comment from the form_For helper. In fields_For, you might need to user :comment or possibly even #comment.
If you are using rails 4, then you will also have a problem with strong parameters: http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html
I'm trying to save the comment text section of a comment and it won't save for some reason.
I'm checking my server outputs, and the comment attribute is set, but when actually saved, it turns out as NIL.
Originally it has "comment"=>{"comment"=>"hello dude"}, "commit"=>"Sbmit Comment"
But in the saving it saves NIL.
Here's my form for comments
<div class="container">
<% if user_signed_in? %>
<%= form_for([#answer, #comment]) do |f| %>
<p>
<%= f.label :comment %>
<%= f.text_area :comment, :cols => "50", :rows => "30"%>
</p>
<p>
<%= f.submit "Submit Comment" %>
</p>
<% end %>
<% else %>
<p> <em>You must be signed in to comment</em> </p>
<% end %>
</div>
Here's my comments controller
class CommentsController < ApplicationController
def create
#answer = Answer.find(params[:answer_id])
#comment = #answer.comments.new(params[:comments])
#comment.writer = current_user.username
#comment.save
redirect_to question_path(#answer)
end
end
And here's my model.
class Comment < ActiveRecord::Base
belongs_to :answer
attr_accessible :anonymous, :comment, :writer, :votes
end
Heres my answers model
class Answer < ActiveRecord::Base
has_many :comments, dependent: :destroy
belongs_to :question
attr_accessible :anonymous, :answer, :commenter, :votes, :comments_attributes
end
Any ideas?
EDIT: I've used params[:comment], however, it says I cannot mass assign attributes to answer, even though answer has attr_accessible: :comments_attributes
In this line #comment = #answer.comments.new(params[:comments]) change :comments to :comment
You are trying to save with params[:comments] in your controller but what is being passed would respond to params[:comment]
I am trying to edit a Topic which has many Posts.
Edit page for a Topic has Topic's name and Post's content that can be edited.
The mass-assignment error occurs in topics_controller.rb, update method, post.update_attributes(params[:post]).
How do I avoid mass-assignment error.
topic.rb
class Topic < ActiveRecord::Base
has_many :posts, :dependent => :destroy
belongs_to :forum
accepts_nested_attributes_for :posts, :allow_destroy => true
attr_accessible :name, :last_post_id, :posts_attributes
end
post.rb
class Post < ActiveRecord::Base
belongs_to :topic
attr_accessible :content
end
topics_controller.rb
def update
#topic = Topic.find(params[:id])
post = #topic.posts.first
if #topic.update_attributes(params[:topic]) && post.update_attributes(params[:post])
topic = Topic.find(#post.topic_id)
flash[:success] = "Success!"
redirect_to topic_posts_path(topic)
else
render 'edit'
end
end
views/topics/edit.html.erb
<%= form_for #topic do |f| %>
<!-- render 'shared/error_messages_topic' -->
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for #topic.posts.first do |post| %>
<%= render :partial => "posts/form", :locals => {:f => post} %>
<% end %>
<%= f.submit "Edit", class: "btn btn-large btn-primary" %>
<% end %>
views/posts/_form.html.erb
<%= f.label :content %>
<%= f.text_area :content %>
In update method you don't have to update attributes of both the models instead of if #topic.update_attributes(params[:topic]) && post.update_attributes(params[:post]) it should this only if #topic.update_attributes(params[:topic]) it will update the posts automatically.
And change your view from this <%= f.fields_for #topic.posts.first do |post| %> to <%= f.fields_for :posts, #topic.posts.first do |post| %> it will work fine.
For more information read this http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
I am using the nested form gem and i add products dynamically to the form. When i do click "add", another product resource appears but on creation it ERASES the former ones from being created entirely. This is how the scenario goes:
Fill in Location
Choose Date
Fill in Product ( one is already on form)
Add 5 more products (Products 2, 3, 4, 5)
Fill in All Products
"click" Create
Created Product 5
This is how my nested form looks:
<%= nested_form_for #location, :url => products_path(#product) do |f| %>
<%= f.label :business %>
<%= f.text_field :business %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates, :url => products_path(#product) do |d| %>
<%= d.label :date %>
<%= d.date_select :date %>
<%= d.fields_for :products, :url => products_path(#product) do |p| %>
<%= p.text_field :name %>
<%= p.text_field :price %>
<%= p.text_field :tag_list %>
<%= p.link_to_remove "Remove Product" %>
<% end %>
<%= d.link_to_add "Add", :products %>
<% end %>
<%= f.submit "Finish" %>
<% end %>
Controller:
class ProductsController < ApplicationController
def new
#location = Location.new
#product = Product.new
product_date = #location.product_dates.build
product_date.products.build
end
def create
#location = Location.create(params[:location])
if #location.save
flash[:notice] = "Products Created."
redirect_to :action => 'index'
else
render :action => 'new'
end
end
Models:
class User < ActiveRecord::Base
devise
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :products, :dependent => :destroy
end
class Location < ActiveRecord::Base
attr_accessible :address, :business, :product_dates_attributes
has_many :products
has_many :product_dates
accepts_nested_attributes_for :product_dates
end
class ProductDate < ActiveRecord::Base
attr_accessible :date, :products_attributes
belongs_to :location
belongs_to :user
has_many :products
accepts_nested_attributes_for :products
end
class Product < ActiveRecord::Base
attr_accessible :name, :price, :tag_list
belongs_to :user
belongs_to :location
belongs_to :product_date
end
Any Suggestions?
First of all remove the url_for declarations on the fields_for declarations so you get
<%= nested_form_for #location, :url => products_path(#product) do |f| %>
<%= f.label :business %>
<%= f.text_field :business %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates do |d| %>
<%= d.label :date %>
<%= d.date_select :date %>
<%= d.fields_for :products do |p| %>
<%= p.text_field :name %>
<%= p.text_field :price %>
<%= p.text_field :tag_list %>
<%= p.link_to_remove "Remove Product" %>
<% end %>
<%= d.link_to_add "Add", :products %>
<% end %>
<%= f.submit "Finish" %>
<% end %>
What is really confusing is your whole routing and params approach. It's just not right. You have a form_for #location with a :url products_path(#product) This will right royally cause issues with the params that are sent back and there in lies the problem.
Stick with routing to location controller not the products controller by removing the products_path(#product) form your nested_form_for declaration and you will find that you will have all the necessary records saved but you will most likely need to change the redirect_to declaration in the locations_controller create action and the same for the update_action.
But why use the products controller at all when you are dealing with a location? Again this just isn't natural or intuitive.
One last thing. Your remove links won't work as you have not added the necessary :dependent => :destroy declaration to the has_many declarations and you are also missing the :reject_if procs and the :allow_destroy => true declarations on the accepts_nested_attributes declarations.
Can I strongly suggest that you
1) Use either the locations controller or the products controller not both
I mean link to get to this form link_to the locations controller and set everything up there or use form_for #product rather than #location and handle everything in the products controller
2) watch the railscasts that this gem is based on very closely
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
3) Spend some time learning about how rails form view helpers arrange for the params hash to be organised in the controllers actions. In your case, have a close look at your log file for the parameters that come into the create action as things currently stand.
You will most likely see that the params are not nested as you would exect them to be which is why the nested attributes declaration is not behaving as expected