Post embeds many Comments.
_id is an Integer type field for Posts, but a String one - for Comments.
post.rb:
class Post
include Mongoid::Document
include Mongoid::Attributes::Dynamic
field :_id, type: Integer
field :title, type: String
field :content, type: String
embeds_many :comments
accepts_nested_attributes_for :comments
end
comment.rb:
class Comment
include Mongoid::Document
include Mongoid::Attributes::Dynamic
field :_id, type: String
field :content, type: String
embedded_in :post
end
posts_controller.rb:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:_id, :title, :content)
end
end
comments_controller.rb:
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
def index
#post = Post.find(params[:post_id])
#comments = #post.comments
end
def show
end
def new
#post = Post.find(params[:post_id])
#comment = #post.comments.new
end
def edit
#comment = #post.comments.find(params[:id])
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to post_path(#post), notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, post: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
def update
end
def destroy
end
private
def set_comment
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
end
def comment_params
params.require(:comment).permit(:_id, :content)
end
end
When I add comments it saves only the value for the content field for the comment but not its _id which is entered by me. Though this works for the post model:
> db.posts.findOne()
{
"_id" : 23,
"title" : "First Post",
"content" : "Text of the 1st post",
"comments" : [
{
"content" : "Comment for the 1st post"
},
{
"content" : "2nd comment"
},
{
"content" : "asdfagzcbzcv"
}
]
}
I have this app on github which is publicly available at https://github.com/tenzan/blog.git
Let _id field clean :)
From your post object you got by Post.find( params[:post_id] ), you can do post.comments.find( params[:comment_id] ).
There is no optimisation do to with post.comments[ params[:comment_id] ] (if I correctly understand what you were trying to do).
If you realy want to show a cleaner comment id to you users, you can implement yourself a field like custom_id or use the gem acts_as_list.
Related
Hey Stackoverflow community (first time asking for help, searched a lot, found nothing specific for my problem, links appreciated).
I have the following structure:
Employees and Comments.
The Employee has this in its model:
has_many :comments, as: :commentable, dependent: :destroy
The Comment has this in its model:
belongs_to :commentable, polymorphic: true
I have a "show.html" view in the "Employee MVC". In this view I want to show an input textfield to add a comment to an employee. This is not working.
If I click submit, I get an undefined method `constantize' for nil:NilClass Error. (see image)
(On a seperate "new.html" in the "Comment MVC", I can create comments perfectly fine and add them to an employee).
Code:
show.html.slim for the Employee
h1
| Mitarbeiter
i<> = #employee.name
p Was für ein wundervoller Name!
hr
h2 Kommentare:
- #employee.comments.each do |comms|
p => comms.text
hr
**
= simple_form_for Comment.new do |f|
= f.input :text, label: "Neuer Kommentar: "
= f.hidden_field :commentable_id, value: #employee.id
= f.hidden_field :commentable_type, value: #employee.class
= f.submit class: 'btn btn-primary'**
a.btn.btn-success href=edit_employee_path(#employee)
| Bearbeiten
p
a.btn.btn-warning href=employees_path Zurück
class CommentsController < ApplicationController
before_action :set_comment, only: %i[ show edit update destroy ]
# GET /comments or /comments.json
def index
#comments = Comment.all
end
# GET /comments/1 or /comments/1.json
def show
end
# GET /comments/new
def new
klaz_name = params[:commentable_type]
thing_id = params[:commentable_id]
#thing = klaz_name.constantize.find(thing_id)
#comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments or /comments.json
def create
klaz_name = params[:commentable_type]
thing_id = params[:commentable_id]
#thing = klaz_name.constantize.find(thing_id)
#comment = Comment.new(comment_params.merge(commentable: #thing))
respond_to do |format|
if #comment.save
format.html { redirect_to comment_url(#comment), notice: "Comment was successfully created." }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1 or /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to comment_url(#comment), notice: "Comment was successfully updated." }
format.json { render :show, status: :ok, location: #comment }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1 or /comments/1.json
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url, notice: "Comment was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def comment_params
params.require(:comment).permit(:text)
end
end
I tried to do it with a link_to and remote: true, but this didnt help either :/
I'm learning ROR. Trying to build this model: one user can have many store each store can have many product. I've been able to create store linking to its owner but I'm stuck at doing the same for product.
store.rb
class Store < ApplicationRecord
belongs_to :user
has_many :products, :foreign_key => :store_id
end
product.rb
class Product < ApplicationRecord
belongs_to :store
end
products_controller.rb
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:product_name, :product_price, :product_description, :product_tag, :sku_code)
end
end
stores_controller.rb
class StoresController < ApplicationController
before_action :set_store, only: [:show, :edit, :update, :destroy]
# GET /stores
# GET /stores.json
def index
#stores = Store.all
end
# GET /stores/1
# GET /stores/1.json
def show
#products = Product.all
end
# GET /stores/new
def new
#store = Store.new
end
# GET /stores/1/edit
def edit
end
# POST /stores
# POST /stores.json
def create
#store = Store.new(store_params)
#store.user_id = current_user.id
respond_to do |format|
if #store.save
format.html { redirect_to #store, notice: 'Store was successfully created.' }
format.json { render :show, status: :created, location: #store }
else
format.html { render :new }
format.json { render json: #store.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /stores/1
# PATCH/PUT /stores/1.json
def update
respond_to do |format|
if #store.update(store_params)
format.html { redirect_to #store, notice: 'Store was successfully updated.' }
format.json { render :show, status: :ok, location: #store }
else
format.html { render :edit }
format.json { render json: #store.errors, status: :unprocessable_entity }
end
end
end
# DELETE /stores/1
# DELETE /stores/1.json
def destroy
#store.destroy
respond_to do |format|
format.html { redirect_to stores_url, notice: 'Store was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_store
#store = Store.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def store_params
params.require(:store).permit(:store_name, :store_description)
end
end
I expect when creating a product, it will get the store_id immediately. I'm keep getting "store must exist" message
From Rails 5, belongs_to requires the association object to be present. If your product object does not have a valid store_id (nil or inexistent store object), that product object will not be valid.
You can bypass this by allowing the association to be optional
class Product < ApplicationRecord
belongs_to :store, optional: true
end
Or, you should allow store_id as permitted parameter in your products_controller and pass it when you create a new product
# below code I assume that your store table has a column called 'store_name'
<%= form_for #product do |f| %>
<%= f.collection_select :store_id, current_user.stores, :id, :store_name, prompt: 'Please select the store of this product' %>
<%= f.submit %>
<% end %>
I'm new to Stackoverflow & rails, but hello!
I've had a look around and can't quite get everything together.
I'm creating a dashboard that will allow a user to add a new client with 4 different fields. Then allowing the user to add projects, with 8 different fields to a particular client. However, I'm struggling to add a project to a client and get it to show up. I've made my code public at: https://github.com/JackStovell/revenue-dashboard.
Please rip my code to pieces & tell me where I'm going wrong so I can adjust it!
Thanks
Here's some snippets:
Project Model:
class Project < ActiveRecord::Base
belongs_to :client
end
Client model
class Client < ActiveRecord::Base
has_many :projects
end
Projects Controller
class ProjectsController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :set_project, only: [:show, :edit, :update, :destroy]
# GET /projects
# GET /projects.json
def index
#projects = Project.all
#clientnav = Client.all
end
# GET /projects/1
# GET /projects/1.json
def show
#project = Project.find(params[:id])
#clientnav = Client.all
end
# GET /projects/new
def new
#project = Project.new
#client = Client.all
#clientnav = Client.all
end
# GET /projects/1/edit
def edit
#clientnav = Client.all
#client = Client.all
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
#clientnav = Client.all
end
# PATCH/PUT /projects/1
# PATCH/PUT /projects/1.json
def update
respond_to do |format|
if #project.update(project_params)
format.html { redirect_to #project, notice: 'Project was successfully updated.' }
format.json { render :show, status: :ok, location: #project }
else
format.html { render :edit }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
#clientnav = Client.all
end
# DELETE /projects/1
# DELETE /projects/1.json
def destroy
#project.destroy
respond_to do |format|
format.html { redirect_to projects_url, notice: 'Project was successfully destroyed.' }
format.json { head :no_content }
end
#clientnav = Client.all
end
def income
#project.income = params[#project.billing] - params[#project.cost]
end
private
# Use callbacks to share common setup or constraints between actions.
def set_project
#project = Project.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def project_params
params.require(:project).permit(:id, :name, :jobNumber, :status, :billing, :cost, :income)
end
end
Clients Controller
class ClientsController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :set_client, only: [:show, :edit, :update, :destroy]
# GET /clients
# GET /clients.json
def index
#clients = Client.all
#clientnav = Client.all
end
# GET /clients/1
# GET /clients/1.json
def show
#client = Client.find(params[:id])
#projects = #client.projects
#clientnav = Client.all
end
# GET /clients/new
def new
#client = Client.new
#clientnav = Client.all
end
# GET /clients/1/edit
def edit
#clientnav = Client.all
end
# POST /clients
# POST /clients.json
def create
#clientnav = Client.all
#client = Client.new(client_params)
respond_to do |format|
if #client.save
format.html { redirect_to #client, notice: 'Client was successfully created.' }
format.json { render :show, status: :created, location: #client }
else
format.html { render :new }
format.json { render json: #client.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /clients/1
# PATCH/PUT /clients/1.json
def update
respond_to do |format|
if #client.update(client_params)
format.html { redirect_to #client, notice: 'Client was successfully updated.' }
format.json { render :show, status: :ok, location: #client }
else
format.html { render :edit }
format.json { render json: #client.errors, status: :unprocessable_entity }
end
end
#clientnav = Client.all
end
# DELETE /clients/1
# DELETE /clients/1.json
def destroy
#client.destroy
respond_to do |format|
format.html { redirect_to clients_url, notice: 'Client was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_client
#client = Client.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def client_params
params.require(:client).permit(:clientName, :clientOwner, :analysis, :analysis2)
end
end
Code:
clients_controller.rb
def new
#client = Client.new
#project = #client.projects.build
end
def create
#client = Client.new(client_params)
#client.save
end
def client_params
params.require(:client).permit(:id, :client_name, ...,
project_attributes: [:name, ...] )
end
projects/_form.html.erb
<%= f.label :clientName %>
<%= f.text_field :clientName"%>
....
....
<%= f.fields_for :projects do |project| %>
<%= project.label :name %>
<%= project.text_field :name%>
....
....
<%end%>
model/client.rb
accepts_nested_attributes_for :projects
ive been having a problem now for 2 days, i followed many videos and tutorials on how to add comments to a post, and for everyone else it seemed to work smoothly.
I got 4 controllers, Users,Posts,Comments and Walls , basically this site is gonna be a facebook clone. So im displaying everything on the Wall index.html.erb
The error im getting is:
No route matches {:action=>"index", :controller=>"comments", :post_id=>nil} missing required keys: [:post_id]
Routes:
Rails.application.routes.draw do
devise_for :users
resources :uploads
resources :users
resources :posts do
resources :comments
end
resources :walls
root 'walls#index'
end
Comments-controller:
class CommentsController < ApplicationController
before_action :find_post
def index
#comments = Comment.all
end
def new
#post = Post.find(params[:post_id])
end
def create
#comment = #post.comments.create(params[:comment].permit(:content))
#comment.post_id = #post.id
#comment.user_id = current_user.id
#comment.save
# #comment = #post.comments.create(params[:comment].permit[:content])
# #comment.post_id = #post.id
respond_to do |format|
if #comment.save
format.html { redirect_to root_path }
# format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
# def comment_params
# params.require(:comment).permit(:content)
# end
def find_post
#post = Post.find(params[:post_id])
end
end
Posts-controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def new
#post = Post.new
#comment = Comment.new
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
#post.user_id = current_user.id
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
#post.user_id = current_user.id
#post.user = current_user
respond_to do |format|
if #post.save
format.html { redirect_to root_path }
# format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
#post.user_id = current_user.id
#post.save
respond_to do |format|
if #post.update(params[:post].permit(:image,:content,:youtube_url))
format.html { redirect_to root_path, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
format.json { respond_with_bip(#post) }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
format.json { respond_with_bip(#post) }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to root_path, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:content, :image, :username, :avatar, :youtube_url,:image_cache)
end
end
I am rendering the form in the index.html.erb for the wall controller index
<%= render "form" %>
And the form loop
views/walls/_form.html.erb
<div class="comments">
<%= form_for ([#post, #post.comments.build]) do |f| %>
byebug
<%= f.text_area :content, class: 'comments js-auto-size', id: 'alex2' ,:rows => 1 %>
<%= f.submit "Submit", class: "btn btn-default" %>
<% end %>
</div>
I dont understand why it cant find the post_id though :/
Since your comments is nested inside posts in routes, you have to pass post_id to the index in CommentsController
class CommentsController < ApplicationController
before_action :find_post
def index
#comments = #post.comments
end
end
# in view
<%= link_to "Comments", post_comments_path(#post) %>
Otherwise, you can define comments to be independent resources so you can do it without passing post_id
Rails.application.routes.draw do
resources :posts
resources :comments
end
My issue is, when I am under the camper show page
Current Camper URL:
campers/1
and I go to click on to view the appointment it uses the camper_id for the appointment_id which is wrong so say if the camper_id is 1 it will use the appointment_id as 1 and actually the appointment id is 3, so then it says Couldn't find appointment with id of 1.
Table Header
<% #appointments.each do |app| %>
<%= link_to app.camper.camperName, appointment_path(#camper, #appointment) %>
Campers Controller Show Action
#appointments = #camper.appointments
Camper Model
has_many :appointments, dependent: :destroy
Appointment Model
belongs_to :camper
Shallow Nested Routes File
resources :customers, shallow: :true do
resources :campers do
resources :appointments do
resources :orders do
member do
patch :complete
end
end
end
end
end
Camper Controller
class CampersController < ApplicationController
before_action :set_camper, only: [:show, :edit, :update, :destroy]
# before_action :set_customer, only: [:index, :new, :edit, :create, :update]
load_and_authorize_resource
# GET /campers
# GET /campers.json
def index
#campers = #customer.campers
end
def list
query = params[:q].presence || ""
#campers = Camper.search(query, page: params[:page], per_page: 20, order: {created_at: :desc} )
end
# GET /campers/1
# GET /campers/1.js
def show
#appointments = #camper.appointments
respond_to do |format|
format.html
format.json
end
end
# GET /campers/new
def new
#customer = Customer.find(params[:customer_id])
#camper = #customer.campers.build
end
# GET /campers/1/edit
def edit
end
def page_name
"Campers"
end
# POST /campers
# POST /campers.json
def create
#camper = Camper.new(camper_params)
respond_to do |format|
if #camper.save
format.html { redirect_to camper_path(#camper), notice: 'Camper was successfully created.' }
format.json { render :show, status: :created, location: #camper }
else
format.html { render :new }
format.json { render json: #camper.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /campers/1
# PATCH/PUT /campers/1.json
def update
respond_to do |format|
if #camper.update(camper_params)
format.html { redirect_to camper_path(#camper), notice: 'Camper was successfully updated.' }
format.json { render :show, status: :ok, location: #camper }
else
format.html { render :edit }
format.json { render json: #camper.errors, status: :unprocessable_entity }
end
end
end
# DELETE /campers/1
# DELETE /campers/1.json
def destroy
#camper.destroy
respond_to do |format|
format.html { redirect_to root_path, notice: 'Camper was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_camper
#camper = Camper.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def camper_params
params.require(:camper).permit(:order_id, :customer_id, :year, :manufacturer, :modelName, :camperClass, :vin, :mileage, :notes, :user_id)
end
end
Appointments Controller
class AppointmentsController < ApplicationController
before_action :set_appointment, only: [:show, :edit, :update, :destroy]
# GET /appointments
# GET /appointments.json
def index
#camper = Camper.find(params[:camper_id])
#appointments = #camper.appointments
end
# GET /appointments/1
# GET /appointments/1.json
def show
#orders = #appointment.orders
end
# GET /appointments/newå
def new
#camper = Camper.find(params[:camper_id])
#appointment = #camper.appointments.build
end
# GET /appointments/1/edit
def edit
end
# POST /appointments
# POST /appointments.json
def create
#appointment = Appointment.new(appointment_params)
respond_to do |format|
if #appointment.save
format.html { redirect_to appointment_path(#appointment), notice: 'Appointment was successfully created.' }
format.json { render :show, status: :created, location: #appointment }
else
format.html { render :new }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /appointments/1
# PATCH/PUT /appointments/1.json
def update
respond_to do |format|
if #appointment.update(appointment_params)
format.html { redirect_to #appointment, notice: 'Appointment was successfully updated.' }
format.json { render :show, status: :ok, location: #appointment }
else
format.html { render :edit }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /appointments/1
# DELETE /appointments/1.json
def destroy
#appointment.destroy
respond_to do |format|
format.html { redirect_to camper_appointments_path(#appointment), notice: 'Appointment was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_appointment
#appointment = Appointment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def appointment_params
params.require(:appointment).permit(:customer_id, :camper_id, :order_id, :title, :description, :date_in, :date_out)
end
end
appointment_path only takes a single appointment argument. Remove the #camper argument:
appointment_path(#appointment)