I'm trying to get my nested form to work. It's a form for a New Album with a space to write a review underneath. The form submits and the Album displays on the page, but the Review does not, it just appears blank. I only am getting one error in the log "Unpermitted parameter: reviews_attributes"
Log:
Started POST "/albums" for ::1 at 2020-04-19 12:10:58 -0400
Processing by AlbumsController#create as HTML
Parameters: {"authenticity_token"=>"jYHM+yeExcTJtENvjQBDsOMo8Ig1g5bRa+hYZ9kCkiI4NO3KP3xdV7SpSZ2IeIOp0wC+5WLxflu22NTIXtoibg==", "album"=>{"artist"=>"Blink 182", "title"=>"California", "avatar"=>#<ActionDispatch::Http::UploadedFile:0x00007fc372d8d5f0 #tempfile=#<Tempfile:/var/folders/26/p006tryd6yb9sp9rq446p07c0000gn/T/RackMultipart20200419-64975-1bp8ang.jpg>, #original_filename="71GfPCWJHXL._SL1500_.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"album[avatar]\"; filename=\"71GfPCWJHXL._SL1500_.jpg\"\r\nContent-Type: image/jpeg\r\n">, "reviews_attributes"=>{"0"=>{"title"=>"Blink 182 review", "date"=>"2020-04-19", "content"=>"NOT THE BLINK182 I KNOW AND LOVE WHERE IS ToM BRING BACK TOM"}}}, "commit"=>"Create Album"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 11], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:10:in `current_user'
Unpermitted parameter: :reviews_attributes
(0.1ms) begin transaction
↳ app/controllers/albums_controller.rb:29:in `create'
Album Create (0.4ms) INSERT INTO "albums" ("artist", "title", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["artist", "Blink 182"], ["title", "California"], ["created_at", "2020-04-19 16:10:58.838672"], ["updated_at", "2020-04-19 16:10:58.838672"]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Blob Load (0.3ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" INNER JOIN "active_storage_attachments" ON "active_storage_blobs"."id" = "active_storage_attachments"."blob_id" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Album"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Attachment Load (0.2ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Album"], ["name", "avatar"], ["LIMIT", 1]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Blob Create (0.3ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["key", "l22w59ulprgmmqrs025woawhi1h6"], ["filename", "71GfPCWJHXL._SL1500_.jpg"], ["content_type", "image/jpeg"], ["metadata", "{\"identified\":true}"], ["byte_size", 137504], ["checksum", "IXxJAt318tAPkwmaLBUW/A=="], ["created_at", "2020-04-19 16:10:58.852999"]]
↳ app/controllers/albums_controller.rb:29:in `create'
ActiveStorage::Attachment Create (0.4ms) INSERT INTO "active_storage_attachments" ("name", "record_type", "record_id", "blob_id", "created_at") VALUES (?, ?, ?, ?, ?) [["name", "avatar"], ["record_type", "Album"], ["record_id", 6], ["blob_id", 11], ["created_at", "2020-04-19 16:10:58.856948"]]
↳ app/controllers/albums_controller.rb:29:in `create'
Album Update (0.2ms) UPDATE "albums" SET "updated_at" = ? WHERE "albums"."id" = ? [["updated_at", "2020-04-19 16:10:58.862445"], ["id", 6]]
↳ app/controllers/albums_controller.rb:29:in `create'
(3.3ms) commit transaction
↳ app/controllers/albums_controller.rb:29:in `create'
Disk Storage (2.5ms) Uploaded file to key: l22w59ulprgmmqrs025woawhi1h6 (checksum: IXxJAt318tAPkwmaLBUW/A==)
[ActiveJob] Enqueued ActiveStorage::AnalyzeJob (Job ID: 9114fadd-5897-4939-9cd6-1d0751f129b2) to Async(active_storage_analysis) with arguments: #<GlobalID:0x00007fc372ddf5d0 #uri=#<URI::GID gid://review-project/ActiveStorage::Blob/11>>
Redirected to http://localhost:3000/albums/6
Completed 302 Found in 63ms (ActiveRecord: 5.5ms | Allocations: 15980)
Nested form (albums/_form.html.erb)
<%= form_for(#album) do |f| %>
<% if #album.errors.any? %>
<ul>
<% #album.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= f.label :artist %>
<%= f.text_field :artist %>
<br><br>
<%= f.label :title %>
<%= f.text_field :title %>
<br><br>
<%= f.label "Album Image:" %><br>
<%= f.file_field :avatar %>
<br><br>
<h2>Write your review of the album</h2>
<%= f.fields_for :reviews do |ff| %>
<%= ff.label :title %>
<%= ff.text_field :title %>
<br>
<%= ff.label :date %>
<%= ff.date_field :date %>
<br>
<%= ff.label :content %>
<%= ff.text_area :content %>
<% end %>
<br>
<%= f.submit %>
<% end %>
<br><br><br>
<%= link_to "Back to Album", albums_path(#album) %>
albums controller:
class AlbumsController < ApplicationController
before_action :set_album, only: [:show, :edit, :update, :destroy]
before_action :must_login, only: [:new, :show, :create, :edit, :update, :destroy]
def index
#albums = Album.all
#user = current_user
end
def show
#review = #album.reviews.build
#review.user = current_user
#review.save
#reviews = Review.recent #scope
end
def new
#album = Album.new
#review = #album.reviews.build
#user = current_user
end
def create
##user = User.find(current_user.id)
#album = current_user.albums.build(album_params)
##album.user_id = current_user.id
#album.reviews.each { |r| r.user ||= current_user } # I'm using ||= so i can use the same code on update without changing reviews that already have a user
if #album.save
redirect_to album_path(#album)
else
render :new
end
end
def edit
#user = current_user
end
def update
##album = current_user.albums.build(album_params)
#album.user_id = current_user.id
if #album.update(album_params)
redirect_to album_path(#album), notice: "Your album has been updated."
else
render 'edit'
end
end
def destroy
#album.delete
#album.avatar.purge
redirect_to albums_path
end
private
def set_album
#album = Album.find(params[:id])
end
def album_params
params.require(:album).permit(:artist, :title, :avatar, :user_id, review_attributes:[:title, :date, :content])
end
end
Reviews controller
class ReviewsController < ApplicationController
before_action :set_review, only: [:show, :edit, :update, :destroy]
before_action :set_current_user, only: [:index, :show, :new, :edit, :destroy]
before_action :find_album, only: [:show, :create, :edit, :update, :destroy]
before_action :must_login, only: [:index, :show, :new, :create, :edit, :update, :destroy]
def index
#albums = Album.with_recent_reviews
end
def show
##reviews = Review.where("album_id = ?", params[:album_id])
end
def new
if params[:album_id] && #album = Album.find_by(id: params[:client_id])
#review = #album.reviews.build
else
redirect_to albums_path
end
end
def create
#review = current_user.reviews.build(review_params)
#review.album = #album
if #review.save
redirect_to album_path(#album)
else
#album = #review.album
render :new
end
end
def edit
end
def update
if #review.update(review_params)
redirect_to album_path(params[:album_id])
else
render 'edit'
end
end
def destroy
if current_user.id == #review.user_id
#album.reviews.find(params[:id]).destroy
redirect_to album_path(params[:album_id])
else
flash[:error] = "Unable to delete your review. Please try again."
redirect_to album_reviews_path(#review)
end
end
private
def set_review
#review = Review.find(params[:id])
end
def set_current_user
#user = current_user
end
def find_album
#album = Album.find(params[:album_id])
end
def review_params
params.require(:review).permit(:title, :date, :content, album_attributes:[:artist, :title, :user_id])
end
end
Album model:
class Album < ApplicationRecord
has_many :reviews
has_many :users, through: :reviews
has_one_attached :avatar
accepts_nested_attributes_for :reviews
validates_presence_of :artist
validates_presence_of :title
scope :with_recent_reviews, -> { includes(:reviews).where(reviews: { date: [(Date.today - 7.days)..Date.tomorrow] }) } #scope relies on include method and custom query on related model (reviews)
end
Review model:
class Review < ApplicationRecord
belongs_to :album, optional: true
belongs_to :user
validates_presence_of :content
validates :title, presence: true, uniqueness: true
validates :date, presence: true
accepts_nested_attributes_for :album
scope :recent, -> { where("date(date) >= ?", Date.today - 7.days) } #scope
end
Routes.rb
Rails.application.routes.draw do
get '/auth/:provider/callback' => 'sessions#omniauth'
get 'auth/failure', to: redirect('/')
get '/signup' => 'users#new', as: 'signup'
post '/signup' => 'users#create'
get '/signin' => 'sessions#new'
post '/signin' => 'sessions#create'
get '/signout' => 'sessions#destroy'
post '/logout', to: "sessions#destroy"
resources :albums do
resources :reviews, except: [:index]
end
resources :users, only: [:show, :destroy]
resources :reviews, only: [:index]
root to: "albums#index"
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
The reviews association is a has_many so fields_for should use the plural form.
= f.fields_for :reviews do |ff|
So that way rails creates that parameter reviews_attributes you are permitting.
If you are still having problems with that change show the new error and stacktrace.
EDIT:
If you want to set the current user id as the user of the review (similar to what you did to assign the current user as the album creator), you can assign that before saving the record:
def create
# #user = User.find(current_user.id) you don need this, you already have the user at current_user, no need to find it again
#album = current_user.albums.build(album_params)
# #album.user = current_user you don't need this, current_user.albums.build already sets this
#album.reviews.each { |r| r.user ||= current_user } # I'm using ||= so you can use the same code on update without changing reviews that already have a user
if #album.save
redirect_to album_path(#album)
else
render :new
end
end
And also, remove the :user_id and :album_id from the permitted parameters for reviews_attributes, you don't want users to exploit that assignation adding those parameters that you are actually not using
Related
In my application I have a goal, this goal belongs to a company and has start and end date, when it is created automatically values are created in the day table that go between the start date and end date defined in the goal, this field has the name of date_day.
In addition to this field each Day has a value field, which is the total amount collected during the day, this value is not automatically defined when the user creates a goal, ie it comes null, it is necessary to edit the Day to define how much was collected in that day. When I go to do the edition of the day I would like to add an employee in my model Salesman, that employee would be tied to that Day.
I managed through the Day edit form to add an employee, but that's it, the edition of the day value is not updated and I also have no increment of the DaySalesman tables.
My models:
class Day < ApplicationRecord
belongs_to :goal
has_many :day_salesmen, dependent: :destroy
has_many :salesmen, through: :day_salesmen
validates_presence_of :date_day, :goal_id
accepts_nested_attributes_for :day_salesmen
end
class DaySalesman < ApplicationRecord
belongs_to :day
belongs_to :salesman
accepts_nested_attributes_for :salesman
end
class Salesman < ApplicationRecord
belongs_to :company
has_many :goal_salesmen, dependent: :destroy
has_many :goals, through: :goal_salesmen
has_many :day_salesmen, dependent: :destroy
has_many :days, through: :day_salesmen
end
Below are my controllers and the result of my controllers:
class DaysController < ApplicationController
before_action :find_day, only: [:show, :edit, :update]
before_action :find_company, only: [:show, :edit]
def index
#day = current_owner.companies.find(params[:company_id]).goal.find(params[:goal_id]).days
end
def show
end
def edit
#dayup = Day.new
#day_salesmen = #dayup.day_salesmen.build
#salesman = #day_salesmen.build_salesman
end
def update
if #day.update(params_day)
flash[:notice] = "Day updated!"
redirect_to company_salesman_path(:id => #day.id)
else
flash.now[:error] = "Could not update day!"
render :edit
end
end
private
def find_company
#company = Company.find(params[:company_id])
end
def find_day
#day = Day.find(params[:id])
end
def params_day
params.require(:day).permit(:value, day_salesman_attributes: [:id, salesman_attributes:[:id, :name]]).merge(goal_id: params[:goal_id])
end
end
Salesman:
class SalesmenController < ApplicationController
before_action :find_salesman, only: [:edit, :update, :destroy]
def index
#salesmen = current_owner.companies.find(params[:company_id]).salesman
#company = Company.find(params[:company_id])
end
def create
#salesman = Salesman.new(params_salesman)
if #salesman.save
flash[:notice] = "Salesman saved!"
else
flash.now[:error] = "Cannot create salesman!"
render :new
end
end
def update
if #salesman.update(params_salesman)
flash[:notice] = "salesman updated!"
else
flash.now[:error] = "Could not update salesman!"
render :edit
end
end
def destroy
#salesman.destroy
end
private
def find_salesman
#salesman = Salesman.find(params[:id])
end
def params_salesman
params.require(:day).require(:salesman).permit(:name, :id).merge(company_id: params[:company_id])
end
end
My controller day view edit is:
<%= render "shared/sidebar2" %>
<div class="container">
<div class="row">
<div class="col s10 offset-s2">
<div class="row">
<h4>Edit day</h4>
<%= form_for(#dayup, url: company_salesmen_path) do |f| %>
<%= f.label :value_of_day %>
<%= f.number_field :value %>
<%= f.fields_for :day_salesman do |ff| %>
<%= f.fields_for :salesman do |fff| %>
<%= fff.label :names_of_salesmen %>
<%= fff.text_field :name %>
<% end %>
<% end %>
<%= f.submit "Create" %>
<% end %>
</div>
</div>
</div>
</div>
My log when I click the submit button on this view is:
Started POST "/companies/1/salesmen" for 172.26.0.1 at 2017-10-31 22:11:56 +0000
Cannot render console from 172.26.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by SalesmenController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"CQaRlVPYsPK8ilOQJCdw04htgXFkUQOKEVsOIDAmRXOM1X3QO+HfOzY2PGnmItMTK9jRj0YFZDYRJPg7qBV27A==", "day"=>{"value"=>"100", "salesman"=>{"name"=>"Renata"}}, "commit"=>"Create", "company_id"=>"1"}
[1m[36mOwner Load (0.7ms)[0m [1m[34mSELECT "owners".* FROM "owners" WHERE "owners"."id" = $1 ORDER BY "owners"."id" ASC LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
[1m[35m (12.4ms)[0m [1m[35mBEGIN[0m
[1m[36mCompany Load (0.4ms)[0m [1m[34mSELECT "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
[1m[35mSQL (111.1ms)[0m [1m[32mINSERT INTO "salesmen" ("name", "company_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"[0m [["name", "Renata"], ["company_id", 1], ["created_at", "2017-10-31 22:11:56.344478"], ["updated_at", "2017-10-31 22:11:56.344478"]]
[1m[35m (36.3ms)[0m [1m[35mCOMMIT[0m
No template found for SalesmenController#create, rendering head :no_content
Completed 204 No Content in 436ms (ActiveRecord: 161.0ms)
I wanted to know how through this day's edit form I can update the value for day, create a new employee and associate it to that day through the Daysalesmen table.
I am getting the below error and unsure how to correct it - your help would be much appreciated.
when at a users show page, i do not get the error, but when at for example at any other page...such as the events index.html page the error displays
No route matches {:action=>"update", :controller=>"friendships", :friend_id=>#<User id: 5, email: "ian#gmail.com"
expanded error in terminal
Started GET "/events" for ::1 at 2016-12-17 12:44:43 +0000
Processing by EventsController#index as HTML
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 4]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 4]]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."email" IS NULL LIMIT 1
Subscription Load (0.1ms) SELECT "subscriptions".* FROM "subscriptions" WHERE "subscriptions"."title" = ? LIMIT 1 [["title", "premium"]]
User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "friendships" ON "users"."id" = "friendships"."friend_id" WHERE "friendships"."user_id" = ? AND "friendships"."status" = ? [["user_id", 4], ["status", "requested"]]
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "friendships" ON "users"."id" = "friendships"."friend_id" WHERE "friendships"."user_id" = ? AND "friendships"."status" = ? [["user_id", 4], ["status", "requested"]]
Rendered shared/_content_dropdownbox_friendrequest.html.erb (4.8ms)
Rendered shared/_header.html.erb (10.7ms)
Rendered events/index.html.erb within layouts/application (11.8ms)
Completed 500 Internal Server Error in 23ms
ActionController::UrlGenerationError - No route matches {:action=>"update", :controller=>"friendships", :friend_id=>#<User id: 5, email: "ian#gmail.com", encrypted_password: "$2a$10$PMO5FPBzjjnFHI/ye8rfP.ONtHP3gagXomj1sbruBXH..."
route file
Rails.application.routes.draw do
resources :friendships, only: [:create, :update, :destroy]
devise_for :users
resources :users
end
views/shared/_content_dropdownbox_friendrequest.html.erb
<ul>
<% current_user.requested_friends.each do |requester| %>
<li>
<%= link_to(image_tag(requester.image_url, :alt => "image", :class =>"#", id: ""), user_path(requester)) %>
<%= link_to truncate("#{requester.firstname} #{requester.lastname}", length: 23), user_path(requester) %>
<%= link_to 'Accept', friendship_path(user_id: current_user, friend_id: requester), controller: "friendships", action: "update", method: :put %>
<%= link_to 'Decline', friendship_path(user_id: current_user, friend_id: requester), controller: "friendships", action: "decline", method: :delete %>
</li>
<div class="clear"></div>
<% end %>
</ul>
frienships_controller
class FriendshipsController < ApplicationController
before_action :authenticate_user!
before_filter :setup_friends
# Sends a friend request.
# We'd rather call this "request", but that's not allowed by Rails.
def create
Friendship.request(#user, #friend)
flash[:notice] = "Request sent."
redirect_to :back
end
# Accepts a friend request.
# We'd rather call this "accept", but that's not allowed by Rails.
def update
#user = User.friendly.find(params[:user_id])
#friend = User.friendly.find(params[:friend_id])
if #user.requested_friends.include?(#friend)
Friendship.accept(#user, #friend)
flash[:notice] = "Connection with #{#friend.firstname} accepted!"
else
flash[:notice] = "No connect request from #{#friend.firstname}."
end
redirect_to :back
end
def destroy
#user = User.friendly.find(params[:user_id])
#friend = User.friendly.find(params[:friend_id])
if #user.requested_friends.include?(#friend) #decline
Friendship.breakup(#user, #friend)
redirect_to :back
elsif #user.pending_friends.include?(#friend) #cancel
Friendship.breakup(#user, #friend)
redirect_to :back
elsif #user.friends.include?(#friend) #delete
Friendship.breakup(#user, #friend)
redirect_to :back
end
end
private
def setup_friends
#user = User.find(current_user.id)
#friend = User.find_by_email(params[:id])
end
end
i am unsure how to solve the error, i tried something like the below but does not work:
<span>
<%= form_for friendship, url: friendship_path(requester), method: :put do |f| %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :friend_id, value: requester.id %>
<%= submit_tag "Accept_test", controller: "friendships", action: "update", class: "btn btn_add_friend" %>
<% end %>
</span>
update controller is waiting for an id parameter, while the only parameters you pass are user_id and friend_id.
You can change your routes to the following
resources :friendships, only: [:create, :destroy] do
collection do
put :update
end
end
I'm trying to update comments on a post in place, and I can get the edit form partial to render correctly, but trying to save does nothing--there's no console error, no error in the server logs, and the record isn't saved.
edit.js.erb
$('#comment-<%= #post.id %>-<%= #comment.id %>').find('.comment-content').html("<%= j render partial: 'comments/comment_form', locals: { comment: comment, post: post } %>");
comments/_comment_form.html.erb
<div class="comment-form col-sm-11">
<%= form_for([post, comment], :remote => true) do |f| %>
<%= f.text_area :content, class: "comment_content", id: "comment_content_#{post.id}" %>
</div>
<div class="col-sm-1">
<%= f.submit "Save", class: "btn btn-primary btn-xs" %>
<% end %>
</div>
update.js.erb
$('comment-form').hide();
$('#comment-<%= #post.id %>-<%= #comment.id %>').find('.comment-content').html('<%= #comment.content %>');
routes.rb
resources :users do
end
resources :posts do
resources :comments
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
end
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
Below is the last thing in the server log when the edit_post_comment_path link is clicked; literally nothing happens when save is clicked in the edit form partial, and a test alert in update.js.erb doesn't fire.
Started GET "/posts/471/comments/30/edit" for 72.231.138.82 at 2016-07-17 01:25:27 +0000
Processing by CommentsController#edit as JS
Parameters: {"post_id"=>"471", "id"=>"30"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 2]]
RailsSettings::SettingObject Load (0.2ms) SELECT "settings".* FROM "settings" WHERE "settings"."target_id" = ? AND "settings"."target_type" = ? [["target_id", 2], ["target_type", "User"]]
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? ORDER BY "posts"."created_at" DESC LIMIT 1 [["id", 471]]
Comment Load (0.2ms) SELECT "comments".* FROM "comments" WHERE "comments"."user_id" = ? AND "comments"."id" = ? LIMIT 1 [["user_id", 2], ["id", 30]]
Comment Load (0.1ms) SELECT "comments".* FROM "comments" WHERE "comments"."id" = ? LIMIT 1 [["id", 30]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 2]]
Rendered comments/_comment_form.html.erb (1.2ms)
Rendered comments/edit.js.erb (13.8ms)
Completed 200 OK in 102ms (Views: 34.4ms | ActiveRecord: 1.7ms)
I have similar create, destroy and custom actions (including an update_attributes method) that are firing correctly, so I'm not sure why this form can't submit. Any help is appreciated, I'm very new to js.
Update with the comment controller actions:
class CommentsController < ApplicationController
before_action :set_post
before_action :user_signed_in?, only: [:create, :destroy]
before_action :authenticate_user!, only: [:create, :edit, :new, :destroy, :update]
before_action :correct_user, only: [:edit, :update, :destroy]
...
def edit
#comment = Comment.find(params[:id])
respond_to do |format|
format.js { render 'comments/edit', locals: {comment: #comment, post: #post } }
end
end
def update
#comment = Comment.find(params[:id])
respond_to do |format|
format.js
end
if #comment.update_attributes(comment_params)
#comment.toggle!(:edited)
flash[:success] = "Comment edited!"
redirect_to root_path
else
render 'edit'
end
end
private
def comment_params
params.require(:comment).permit(:content, :user_id, :post_id)
end
def set_post
#post = Post.find(params[:post_id])
end
def correct_user
#comment = current_user.comments.find_by(id: params[:id])
redirect_to root_url if #comment.nil?
redirect_to root_url if #comment.userlocked?
end
end
I've updated the edit form with :method => :put, to no effect, and thanks for the typo catch #Emu.
As you're submitting an edit form, you should define the method in the form like:
<%= form_for([post,comment ], :remote=>true, :method => :put) do |f| %>
Also, in the update.js.erb the following line missing the "." or "#"
$('.comment-form').hide();
What is the best way to validate a answer input by a user, validation rules below:
Examples of formats allowed 1, 2, 3, 4...to 12
The value is 2 answers for 12 choices
model:
class Questions < ApplicationRecord
belongs_to :user
validates :user, presence: true
validates :answers, presence: true
end
Html:
<h3>question</h3>
<% (1..12).each do |x| %>
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-danger btn-circle">
<input type="checkbox" name="question[answer][]" id="optionsCheckbox<%= x %>" value="<%= x %>" />
<%= x %>
</label>
</div>
<% end %>
</ul>
<%= f.button :submit, "submit", class: "btn btn-success" %>
in controller:
class QuestionsController < ApplicationController
skip_before_action :authenticate_user!, only: [ :new ]
before_action :find_question, only: [:show, :edit, :update, :destroy]
def create
#question = Question.new(ticket_params)
#question.user = current_user
if #question.save
redirect_to new_charge_path
else
render :new, alert: "Oops, something went wrong..."
end
end
def question_params
params.require(:question).permit(answer: [])
end
def find_question
#question = Question.find(params[:id])
end
end
answer is a string in questions table
It is an array, he have 12 choices and 2 possible responses. Like a multiple choice quiz.. I would just define the possible number of choice (2 choices)
That is my submit response in console:
Started POST "/questions" for 127.0.0.1 at 2016-05-24 18:26:08 +0200
Processing by QuestionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"mAoBIf9jqDoungeeFKe6KitIf0ahAxhi6rVODmz6v1xGExYeVAVL8qXBfJj37KTpIkBBZJV2F1MRuBJKA==", "question"=>{"answer"=>["2", "8"], "commit"=>"Submit"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT 2 [["id", 6], ["LIMIT", 1]]
(0.2ms) BEGIN
SQL (27.0ms) INSERT INTO "questions" ("answer", "created_at", "updated_at", "user_id") VALUES (1, 2 ) RETURNING "id" [["answer", "[\"2\", \"8\"]"], ["created_at", 2016-05-24 16:26:08 UTC], ["updated_at", 2016-05-24 16:26:08 UTC], ["user_id", 6]]
(23.5ms) COMMIT
Redirected to http://localhost:3000/charge/new
Completed 302 Found in 112ms (ActiveRecord: 51.3ms)
Not sure I fully understand the requirement, but seems like something like this:
class Question...
validate :validate_answers
def validate_answers
unless answers.length == 2
errors.add(:answers, 'must have 2 selected')
end
end
end
Trying to learn RoR. Currently adding comments to posts by user. So far I have a posts model, comments model and post_comments model (to associate the two). So for in 'rails console' I can run: (say I set p = Post.first and c = Comment.first)
p.comments << c
This forms an association so it works in the console. I just can't seem to get the comments to form this association from the UI. So far I am creating the comments at "comments/new" (not sure if this is the issue. Do they need to be created on the "show view" for "post").
Here are some code snippets
Controllers
comments_controller.rb
class CommentsController < ApplicationController
def index
#comment = Comment.all
end
def new
#comment = Comment.new
end
def create
#comment = Comment.new(commentParams)
if #comment.save
flash[:success] = "Comment successfully added"
redirect_to comments_path(#comment)
else
render 'new'
end
end
def show
#comment = Comment.find(params[:id])
end
private
def commentParams
params.require(:comment).permit(:comment)
end
end
posts_controller
class PostsController < ApplicationController
before_action :setPost, only: [:edit, :update, :show, :destroy, :sold]
before_action :requireUser, except: [:index, :show]
before_action :requireSameUser, only: [:edit, :update, :destroy, :sold]
def index
#posts = Post.paginate(page: params[:page], per_page: 20)
end
def new
#post = Post.new
end
def create
#post = Post.new(postParams)
#post.user = currentUser
if #post.save
flash[:success] = "Post successfully added."
redirect_to post_path(#post)
else
render 'new'
end
end
def update
if #post.update(postParams)
flash[:success] = "Post successfully updated."
redirect_to post_path(#post)
else
render 'edit'
end
end
def show
end
def edit
end
def sold
#post.toggle(:sold)
#post.save
redirect_to post_path(#post)
end
def destroy
#post.destroy
flash[:danger] = "Item successfully deleted."
redirect_to posts_path
end
private
def postParams
params.require(:post).permit(:title, :price, :description, category_ids:[])
end
def setPost
#post = Post.find(params[:id])
end
def requireSameUser
if currentUser != #post.user and !currentUser.admin
flash[:danger] = "You can only edit or delete your own items"
redirect_to root_path
end
end
end
Models
comment.rb
class Comment < ActiveRecord::Base
belongs_to :post_comments
belongs_to :user
belongs_to :post
end
post_comment.rb
class PostComment < ActiveRecord::Base
belongs_to :post
belongs_to :comment
end
post.rb
class Post < ActiveRecord::Base
belongs_to :user
has_many :post_categories
has_many :categories, through: :post_categories
has_many :post_comments
has_many :comments, through: :post_comments
validates :title, presence: true,
length: { minimum: 4, maximum: 20 }
validates :description, presence: true,
length: { maximum: 1000 }
validates :user_id, presence: true
end
Views
posts/show.html.erb
<p>Comments: <%= render #post.comments %></p>
This renders the partial below
comments/_comment.html.erb
<%= link_to comment.name, comment_path(comment) %>
Finally is the new comment page as it is.
comments/new.html.erb
<h1>New Comment</h1>
<%= render 'shared/errors', obj: #comment %>
<div class="row">
<div class="col-xs-12">
<%= form_for(#comment, :html => {class: "form-horizontal", role: "form"}) do |f| %>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :comment %>
</div>
<div class="col-sm-8">
<%= f.text_area :comment, rows: 3, class: "form-control", placeholder: "Please enter a comment", autofocus: true %>
</div>
</div>
<div class="form-group">
<div class="center col-sm-offset-1 col-sm-10">
<%= f.submit class: "btn btn-primary btn-lg" %>
</div>
</div>
<% end %>
Any help would be greatly received.
Update
Log
Started GET "/posts/2" for ::1 at 2016-01-15 12:39:55 +0000
Processing by PostsController#show as HTML
Parameters: {"id"=>"2"}
[1m[36mPost Load (0.1ms)[0m [1mSELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1[0m [["id", 2]]
[1m[35mUser Load (0.1ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
[1m[36m (0.1ms)[0m [1mSELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = ?[0m [["user_id", 1]]
[1m[35mCategory Exists (0.1ms)[0m SELECT 1 AS one FROM "categories" INNER JOIN "post_categories" ON "categories"."id" = "post_categories"."category_id" WHERE "post_categories"."post_id" = ? LIMIT 1 [["post_id", 2]]
[1m[36mCategory Load (0.0ms)[0m [1mSELECT "categories".* FROM "categories" INNER JOIN "post_categories" ON "categories"."id" = "post_categories"."category_id" WHERE "post_categories"."post_id" = ?[0m [["post_id", 2]]
Rendered categories/_category.html.erb (0.2ms)
[1m[35mComment Load (0.1ms)[0m SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 2]]
Rendered comments/_comment.html.erb (0.1ms)
Rendered posts/show.html.erb within layouts/application (6.5ms)
[1m[36mCategory Load (0.1ms)[0m [1mSELECT "categories".* FROM "categories"[0m
Rendered layouts/_navigation.html.erb (0.9ms)
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/_footer.html.erb (0.1ms)
Completed 200 OK in 52ms (Views: 50.3ms | ActiveRecord: 0.5ms)
As a comment can belong to a single post only, you do not need an association table (post_comments). You just need a simple one-to-many relationship.
Your post comment would be:
class Post < ActiveRecord::Base
has_many :comments
...
end
And comment would be like this:
class Comment < ActiveRecord::Base
belongs_to :post
...
end
Just make sure that you have the necessary post_id column in the comments table (you can check the db/schema.rb file). If that is missing, you can use the following migration to add it:
class AddPostIdToComments < ActiveRecord::Migration
def change
add_column :comments, :post_id, :integer
add_index :comments, :post_id
end
end
You also need to make sure you keep somewhere the reference to the post, whenever a user tries to create a comment to a post. You can add this in a hidden field to your comments/new.html.erb template. You could set the hidden field in the new action, in PostsController, after passing it through the URL.
So, in your posts/show.html.erb template you would have:
<%= link_to "Add Comment", new_comment_path(post_id: #post.id) %>
In your new action, in PostsController:
def new
#comment = Comment.new(post_id: params[:post_id])
end
And finally the hidden field in your form would be:
<%= f.hidden_field :post_id %>
Finally, add the post_id parameter to the list of permitted parameters in CommentsController.
instead of
In your new action, in PostsController:
def new
#comment = Comment.new(post_id: params[:post_id])
end
you can use this in the form views
<%= form.hidden_field :post_id, value: "#{params[:post_id]}" %>