I have a very basic Photo and Comments model that works and then I have a built a Cflags model that is used to flag comments. I am getting the following error from Heroku log when I visit the photos/show.html.erb view.
ActionView::Template::Error (uninitialized constant ActionView::CompiledTemplates::Cflags
photos/show.html.erb
.
.
<% #photo.comments.each do |comment| %>
<%= form_for([comment, Cflags.new]) do |f| %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.submit "Report Inappropiate" %>
<% end %>
<% end %>
resources :photos do
resources :comments do
resources :cflags
end
end
PhotosController
def show
#photo = Photo.approved.find(params[:id])
end
CommentsController
def create
#photo = Photo.find(params[:photo_id])
#comment = #photo.comments.build(comment_params)
#comment.save
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
class Cflag < ActiveRecord::Base
belongs_to :comment, counter_cache: true
belongs_to :user, counter_cache: true
validates :user_id, presence: true
validates :comment_id, presence: true
validates :user_id, uniqueness: {
scope: [:comment_id],
message: 'You can only flag a comment once. Thank you for your feedback.'
}
default_scope -> { order(created_at: :desc) }
end
class CflagsController < ApplicationController
before_action :logged_in_user
def new
end
def create
#comment = Comment.find(params[:comment_id])
#cflag = #comment.cflags.build(cflag_params)
if #cflag.save
if #comment.cflags_count > 1
#comment.update_attribute(:approved, false)
flash[:success] = "Flag created! Comment ##{#comment.id} has been removed for review. Thank you for your feedback"
redirect_to :back
else
flash[:success] = "Flag created! Thank you for your feedback"
redirect_to :back
end
else
redirect_to :back, notice: #cflag.errors.full_messages
end
end
private
def cflag_params
params.require(:cflag).permit(:user_id, :comment_id).merge(user_id: current_user.id)
end
end
create_table "cflags", force: :cascade do |t|
t.integer "comment_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "cflags", ["comment_id"], name: "index_cflags_on_comment_id"
add_index "cflags", ["user_id"], name: "index_cflags_on_user_id"
You have a typo. You model is called Cflag not Cflags. Change this:
photos/show.html.erb
.
.
<% #photo.comments.each do |comment| %>
<%= form_for([comment, Cflags.new]) do |f| %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.submit "Report Inappropiate" %>
<% end %>
<% end %>
to this
photos/show.html.erb
.
.
<% #photo.comments.each do |comment| %>
<%= form_for([comment, Cflag.new]) do |f| %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.submit "Report Inappropiate" %>
<% end %>
<% end %>
Related
NoMethodError in PostsController#create
undefined method `posts' for nil:NilClass
Posts#controller
class PostsController < ApplicationController
# before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
before_action :find_postable, except: [:index]
def index
#posts = Post.all.order('created_at DESC')
end
def new
#post = Post.new
end
def create
#post = #postable.posts.new post_params
if #post.save
redirect_to :back, notice: 'Your comment was successfully posted!'
else
redirect_to :back, notice: "Your comment wasn't posted!"
end
end
def destroy
Post.find(params[:id]).destroy
redirect_to posts_path#, notice: "Post successfully deleted"
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update_attributes(student_params)
redirect_to post_path
else
redirect_to edit_post_path
end
end
def show
#post = Post.find (params[:id])
end
private
def post_params
params.require(:post).permit(:content, :image, :document, :audio, :video, :classroom_id)
end
def correct_user
#post = current_user.posts.find_by(id: params[:id])
redirect_to root_url if #post.nil?
end
def find_postable
#postable = Post.find_by_id(params[:post_id]) if params[:post_id]
#postable = Classroom.find_by_id(params[:classroom_id]) if params[:classroom_id]
end
Here is the post model
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :classroom
belongs_to :postable, polymorphic: true
has_many :posts, as: :postable
end
Here is the classroom model (it belongs to the class and this is selected in the new post form"
class Classroom < ActiveRecord::Base
has_many :posts, as: :postable
belongs_to :teachers
# belongs_to :students
Posts in Schema.rb
create_table "posts", force: :cascade do |t|
t.text "content"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "classroom_id"
t.integer "postable_id"
t.string "postable_type"
end
I've tried many things with no success, I'm not quite sure why I'm getting this error. I'm following a video and trying to apply it to my existing post model but am still having trouble. Thanks
New Post Form:
<%= form_for :post, html: { multipart: true, class: "post-form" }, url: posts_path do |f| %>
<h4>Choose a Classroom</h4>
<div class="form-group">
<%= f.collection_select :classroom_id, current_user.classrooms, :id, :name %>
</div>
<h4>Write a post</h4>
<div class="form-group">
<%= f.text_area :content, class: "form-control" %>
</div>
<h4>Attach Files</h4>
<div class="form-group">
<%= f.file_field :image %>
</div>
<%= f.submit "Add Post", class: "btn btn-primary" %>
<% end %>
For a post reply
<li>
<%= post.content %> -
<%= form_for [post, Post.new] do |f| %>
<%= f.text_area :content, placeholder: "Add a Reply" %><br/>
<%= f.submit "Reply" %>
<% end %>
</li>
The error is in find_postable method, specifically in this line:
#postable = Classroom.find_by_id(params[:classroom_id]) if params[:classroom_id]
You are trying to fetch classroom_id from params (i.e. params[:classroom_id]) but that key (classroom_id) exists within post key in your parameters hash:
Parameters: {
"utf7"=>"✓",
"authenticity_token"=>"bunchofletters==",
"post"=>{
"classroom_id"=>"1",
"content"=>"hello"
},
"commit"=>"Add Post"
}
To fix this, change params[:classroom_id] to params[:post][:classroom_id] in find_postable method:
def find_postable
#postable = Post.find_by_id(params[:post_id]) if params[:post_id]
#postable = Classroom.find_by_id(params[:post][:classroom_id]) if params[:classroom_id]
end
I used nested_form gem and I am trying to build a form which has fields from two tables(Project, Question).
My model:
class Project < ApplicationRecord
has_many :questions
accepts_nested_attributes_for :questions
end
class Question < ApplicationRecord
belongs_to :project
end
My controller:
class ProjectsController < ApplicationController
layout 'application'
def index
#projects = Project.all
end
def show
#project = Project.find(params[:id])
end
def new
#project = Project.new
#questions = #project.questions.build
end
def create
#project = Project.new(project_params)
#project.save
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
def project_params
params.require(:project).permit(:name, question_attributes: [:id, :content, :_delete])
end
end
My view:
<%= nested_form_for(#project) do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% #project.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>
<%= f.fields_for :questions do |builder| %>
<%= render "question_fields", :ff => builder %>
<% end %>
<p>
<%= f.link_to_add "Add a questions",:questions %>
</p>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And my schema file :
create_table "projects", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "questions", force: :cascade do |t|
t.integer "project_id"
t.string "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["project_id"], name: "index_questions_on_project_id", using: :btree
end
And _question_fields file is :
<p>
<%= ff.label :content, "Question" %>
<%= ff.text_area :content%>
<%= ff.link_to_remove "Remove this task"%>
</p>
Table Project will be saved but the table Question could not be saved.Why?
After change this line of code
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :_delete])
end
I get the following error:
1 error prohibited this project from being saved:
Questions project must exist
I applied the change too ,but this time nothing could not be saved.
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :project_id, :_delete])
end
The issue is with the project_params. As you have has_many :questions, the question_attributes should be changed to questions_attributes
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :_delete])
end
Update:
Questions project must exist
Either permit project_id in questions_attributes
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :project_id, :_delete])
end
or set optional: true on the association
class Question < ApplicationRecord
belongs_to :project, optional: true
end
everything was working until I add the form_for for creating comments and I get this error undefined method `user_name' for nil:NilClass...
I searching for hours for solution but in vain..
here is my posts views index file with the form I added for creating the comments:
<div class="row">
<div class="col-md-12">
<%= render 'form' %>
<div id="posts" class="transitions-enabled">
<% #posts.each do |post| %>
<div class="box box-1 panel panel-default">
<div class="panel-body">
<%= link_to image_tag(post.user.avatar.url, size: "50x50", class: "img-circle"), profile_path(post.user.user_name) %>
<ul class="posts-shows">
<li><strong><%= link_to post.user.user_name, profile_path(post.user.user_name) %></strong></li>
<li><small><%= link_to "#{time_ago_in_words(post.created_at)} ago", post_path(post), class: "time-link" %> </small></li>
</ul>
<p class="disc-posts"><%= post.description %></p>
<%= link_to image_tag(post.image.url(:large), class: "img-responsive img-in" ) %><br/>
<% if post.user == current_user %>
<div><%= link_to "Edit", edit_post_path(post) %> | <%= link_to "delete", post, method: :delete, data: {confirm: "Are you sure?"} %> </div>
<% else %>
<div><%= link_to "Repost", repost_post_path(post), method: :post, data: { confirm: "Are you sure?"} if user_signed_in? %></div>
<% end %>
</div>
<%= form_for([post, post.comments.build]) do |f| %>
<p>
<%= f.label :content %><br>
<%= f.text_area :content, class: "form-control" %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<% if post.comments.present? %>
<div class="panel-footer">
<% post.comments.each do |comment| %>
<%= link_to image_tag(post.user.avatar.url, size: "30x30", class: "img-circle"), profile_path(comment.user.user_name) %>
<%= link_to comment.user.user_name, profile_path(comment.user.user_name), class: "username-size" %>
<%= comment.content %>
<% if comment.user == current_user %>
<%= link_to "delete", post_comment_path(post, comment), method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
here is the form_for alone:
<%= form_for([post, post.comments.build]) do |f| %>
<p>
<%= f.label :content %><br>
<%= f.text_area :content, class: "form-control" %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
and here is my comment, user and post model that shows the associations :
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
.........................
class Post < ActiveRecord::Base
validates_presence_of :description
belongs_to :user
has_many :comments, dependent: :destroy
end
......................
class User < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :posts, dependent: :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :user_name, presence: true, length: { minimum: 4, maximum: 16 }
end
and my comments controller:
class CommentsController < ApplicationController
before_action :set_post
def index
#comments = #post.comment.all
end
def new
#comment = #post.comments.build(comments_params)
end
def create
#comment = #post.comments.build(comments_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to :back
else
flash[:alert] = "Check the comment form"
render root_path
end
end
def edit
end
def update
end
def destroy
#comment = #post.comments.find(params[:id])
#comment.destroy
flash[:success] = "Comment deleted :("
redirect_to root_path
end
private
def comments_params
params.require(:comment).permit(:content)
end
def set_post
#post = Post.find(params[:post_id])
end
end
my schema:
create_table "comments", force: :cascade do |t|
t.integer "user_id"
t.integer "post_id"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
create_table "posts", force: :cascade do |t|
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image"
t.integer "user_id"
t.integer "original_post_id"
end
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
seems like few comments don't have user_id in this line
<%= link_to comment.user.user_name, profile_path(comment.user.user_name), class: "username-size" %>
Try destroying the comments with user_id having nil value
Comment.destroy_all(user_id: nil)
Are you sure your post table have user_id or others foreign key ?
You can use :
belongs_to :user, :foreign_key => 'user_id' at post.rb model
And :
has_many :posts, :foreign_key => 'user_id' at user.rb
I'm pretty new to Rails myself, but I've worked through similar errors a dozen times. This bit appears to be a problem:
profile_path(post.user.user_name)
Earlier in the same line of code, you use:
link_to post.user.user_name
but that part seems okay, because it's just the displayed text.
In the actual link, I don't think you should include the user_name. Try simply using "post.user" instead.
I have been trying to figure out how to upload multiple images to one model through a nested model for a while now with no luck. I have a Project model, and for each project i would like to upload multiple images. I created a model called Picture and nested it within the Project model, and have set up paperclip and everything seems fine except when I upload an image and click on "Create project", the image does not show on the "show" page. There is no error message displayed. Please help as I do not know how to proceed from here.
here is my code:
Project form:
<%= bootstrap_nested_form_for #project, :html => {:multipart => true} do |f| %>
<% f.fields_for :pictures do |builder| %>
<% if builder.object.new_record? %>
<p>
<%= builder.file_field :image %>
</p>
<% end %>
<%= builder.link_to_remove "Remove" %>
<% end %>
<p>
<%= f.link_to_add "Add Images", :pictures %>
</p>
<%= f.submit %>
<% end %>
Project controller:-
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#projects = Project.all
respond_with(#projects)
end
def show
respond_with(#project)
end
def new
#project = Project.new
#project.pictures.build
respond_with(#project)
end
def edit
#project = Project.find(params[:id])
#project.pictures.build
end
def create
#project = Project.new(project_params)
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
def update
#project.update(project_params)
respond_with(#project)
end
def destroy
#project.destroy
respond_with(#project)
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:id, :title, :description, :status, :phase, :location, pictures_attributes: [:id, :image])
end
end
Projects model:-
class Project < ActiveRecord::Base
has_many :pictures, :dependent => :destroy
accepts_nested_attributes_for :pictures, :reject_if => lambda { |t| t['picture'].nil? }
end
Pictures model:-
class Picture < ActiveRecord::Base
belongs_to :project
has_one :image
has_attached_file :image,
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename",
:styles => { :medium => "300x300>", :thumb => "100x100>" }
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
end
Show page:-
<% #project.pictures do |picture| %>
<%= image_tag picture.image_url %>
<% end %>
<p>
<strong>Title:</strong>
<%= #project.title %>
</p>
<p>
<strong>Description:</strong>
<%= #project.description %>
</p>
<p>
<strong>Status:</strong>
<%= #project.status %>
</p>
<p>
<strong>Phase:</strong>
<%= #project.phase %>
</p>
<p>
<strong>Location:</strong>
<%= #project.location %>
</p>
<%= link_to 'Edit', edit_project_path(#project) %> |
<%= link_to 'Back', projects_path %>
schema :-
ActiveRecord::Schema.define(version: 20150728092717) do
create_table "pictures", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "project_id"
end
add_index "pictures", ["project_id"], name: "index_pictures_on_project_id"
create_table "projects", force: true do |t|
t.string "title"
t.text "description"
t.string "status"
t.string "phase"
t.string "location"
t.datetime "created_at"
t.datetime "updated_at"
end
Your form and whitelist uses the property name image.
But you are rejecting any nested pictures if they don't have the picture param.
accepts_nested_attributes_for :pictures, :reject_if => lambda { |t| t['picture'].nil? }
Nested attributes params are not wrapped in a "model key" like rails form params usually are. This is what they look like:
params = {
project: {
pictures_attributes: [
{
image: 'foo.jpg'
}
]
}
}
You can catch these kind of errors quite simply with model specs:
require 'rails_helper'
RSpec.describe Project do
it 'accepts nested pictures' do
project = Project.new(pictures_attributes: [{ image: 'foo.jpg' }])
expect(project.pictures.first).to to_be_a Picture
end
end
The attachment won't save. What I am missing here?
In my application I have a project ,for each project user can upload many assets. The Upload is done by carrier wave.
here are the models
class Project < ActiveRecord::Base
has_many :assets,:as => :assetable,dependent: :destroy
accepts_nested_attributes_for :assets, :allow_destroy => true
end
class Asset < ActiveRecord::Base
belongs_to :project
belongs_to :user
belongs_to :assetable, :polymorphic => true
mount_uploader :attachment, AttachmentUploader #carrierwave
validates :attachment, presence: true
validates :project_id, presence: true
end
and these are the actions in my project_controller
def new
#project = Project.new
#asset = #project.assets.build
end
def create
#project = Project.new(project_params)
#project.assets.build
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
def project_params
params.require(:project).permit(:user_id, :summary, :start_date,assets_attributes: [:id, :project_id, :attachment,:user_id] )
end
this is how the form looks like
<%= form_for #project,:html => {:multipart => true } do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
</div>
<% end %>
<%= f.fields_for :assets do |p| %>
<div class="field">
<%= p.label :attachment %><br>
<%= p.file_field :attachment,name: "assets[attachment][]" %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
schema.rb
create_table "assets", force: true do |t|
t.string "assetable_id"
t.string "assetable_type"
t.string "attachment"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "projects", force: true do |t|
t.string "user_id"
t.string "summary"
t.datetime "created_at"
t.datetime "updated_at"
end
projects/_form.html.erb
<%= form_for #project, :html => {:multipart => true } do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<%= #project.errors.inspect %>
</div>
<% end %>
<%= f.label :summary %>
<%= f.text_field :summary %>
<%= f.fields_for :assets do |p| %>
<div class="field">
<%= p.label :attachment %><br>
<%= p.file_field :attachment %>
<%= p.hidden_field :assetable_id %>
<%= p.hidden_field :assetable_type %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
projects_controller.rb
# GET /projects/new
def new
#project = Project.new
#project.assets.build
end
# POST /projects
# POST /projects.json
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def project_params
params.require(:project).permit(:user_id, :summary, :start_date, assets_attributes: [:id, :assetable_id, :assetable_type, :attachment, :user_id] )
end
project.rb
class Project < ActiveRecord::Base
has_many :assets, :as => :assetable, dependent: :destroy
accepts_nested_attributes_for :assets, :allow_destroy => true
end
asset.rb
class Asset < ActiveRecord::Base
belongs_to :project
belongs_to :assetable, :polymorphic => true
mount_uploader :attachment, AttachmentUploader #carrierwave
validates :attachment, presence: true
validates :assetable_type, presence: true
end
Aside
Since you based this question off a previous question you asked I'll just mention: You only want to use a polymorphic association if you intend instances of your asset class to belong to different types of classes (ie. things other than a project).