Nested Attribute Image Uploads Not Updating (Rails 4/ Carrierwave) - ruby-on-rails

I'm using this example to create multiple image uploads using Carrierwave Rails 4 multiple image or file upload using carrierwave. For some reason if I edit the Post and try to upload a different image it doesn't update.
listings_controller.rb
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, :except => [:show, :index]
def index
#listings = Listing.order('created_at DESC')
respond_to do |format|
format.html
format.json { render json: #listings }
end
end
def show
#image_attachments = #listing.image_attachments.all
end
def new
#listing = Listing.new
#listing.user = current_user
#image_attachment = #listing.image_attachments.build
end
def edit
end
def create
#listing = Listing.new(listing_params)
#listing.created_at = Time.now
#listing.user = current_user
respond_to do |format|
if #listing.save
params[:image_attachments]['image'].each do |a|
#image_attachment = #listing.image_attachments.create!(:image => a, :listing_id => #listing.id)
end
format.html { redirect_to #listing, notice: 'Post was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #listing.update(listing_params)
flash[:notice] = 'Deal was successfully updated.'
format.html { redirect_to #listing }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:condition, :listing_title, :nickname, :listing_size, :listing_price, :user_id, image_attachments_attributes: [:id, :listing_id, :image])
end
end
listing form
<%= form_for(#listing, :html => { :class => 'form', :multipart => true }) do |f| %>
<% if #listing.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#listing.errors.count, "error") %> prohibited this listing from being saved:</h2>
<ul>
<% #listing.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :image_attachments do |p| %>
<div>
<%= p.label :image %>
<%= p.file_field :image, :multiple => true, name: "image_attachments[image][]", :class => 'upload' %>
</div>
<% end %>
<div class="actions">
<%= f.submit 'Submit', :class => 'submitButton' %>
</div>
<% end %>
listing.rb
has_many :image_attachments
accepts_nested_attributes_for :image_attachments
Any help? Thanks.
UPDATE
This is the log ouput when I try to update the image field. "about.png" is the new image I'm trying to upload.
Started PATCH "/listings/nike-air-max-90" for 127.0.0.1 at 2014-07-16 11:40:14 -0400
Processing by ListingsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"LU1ADy5JqfuX9CMDtcG/dmGgu9nuvplDQrVixfICsS4=", "listing"=>{"listing_title"=>"Nike Air Max 90", "nickname"=>"", "listing_size"=>"9.5", "listing_price"=>"160", "image_attachments_attributes"=>{"0"=>{"id"=>"1"}}}, "image_attachments"=>{"image"=>[#<ActionDispatch::Http::UploadedFile:0x00000109506810 #tempfile=#<Tempfile:/var/folders/vk/x5f3g8n147z_j39_mzkbfq600000gp/T/RackMultipart20140716-1370-63vlgx>, #original_filename="about.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"image_attachments[image][]\"; filename=\"about.png\"\r\nContent-Type: image/png\r\n">]}, "commit"=>"Submit", "id"=>"nike-air-max-90"}
[1m[35mListing Load (0.2ms)[0m SELECT "listings".* FROM "listings" WHERE "listings"."slug" = 'nike-air-max-90' ORDER BY "listings"."id" ASC LIMIT 1
[1m[36mUser Load (0.2ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1[0m
[1m[35m (0.1ms)[0m begin transaction
[1m[36mImageAttachment Load (0.1ms)[0m [1mSELECT "image_attachments".* FROM "image_attachments" WHERE "image_attachments"."listing_id" = ? AND "image_attachments"."id" IN (1)[0m [["listing_id", 2]]
[1m[35m (0.1ms)[0m commit transaction
Redirected to http://localhost:3000/listings/nike-air-max-90
Completed 302 Found in 5ms (ActiveRecord: 0.6ms)

Option 1 (Replace all existing attachments with new uploaded ones
In your update action, you are NOT doing what you are doing in create action. Which is this:
params[:image_attachments]['image'].each do |a|
#image_attachment = #listing.image_attachments.create!(:image => a, :listing_id => #listing.id)
end
You can't expect Rails to do this for you magically because this is not a typical use of accepts_nested_attributes feature. In fact, in your current code, you are not using this feature at all.
If you want to make it work with your current code, you will have to delete all existing image_attachments and create the new ones in the update action, like this:
def update
respond_to do |format|
if #listing.update(listing_params)
if params[:image_attachments] && params[:image_attachments]['image']
# delete existing image_attachments
#listing.image_attachments.delete_all
# create new ones from incoming params
params[:image_attachments]['image'].each do |a|
#image_attachment = #listing.image_attachments.create!(:image => a, :listing_id => #listing.id)
end
end
flash[:notice] = 'Deal was successfully updated.'
format.html { redirect_to #listing }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
This will replace all existing images with new ones, if you upload new ones.
Option 2 (Edit them individually)
If you want to be able to update existing attachments, you will have to modify the edit form to allow updating attachment records individually. Or do it via proper use of accepts_nested_attributes feature. Cocoon is one great gem help you incorporate nested attributes in your forms easily.

Related

How can I pass IDs from two different models to a new one?

I'm currently trying to pass User_id and Event_id as params for Guest:
Right now in the console, I can create a new guest object using:
Guest.new(user_id: #, event_id: #)
After creating a guest object, I can call 'User.assited_events' to get all the events this user is assisting, same with events I can call 'Event.assitances' to gell all the users assisting this event.
I just want to figure out a way to submit the user_id and event_id from events#index.
I'm using a custom method called 'Assist' inside of Events Controller
def assist
#guest = Guest.create(:user_id => User.find(session[:current_user_id]), :event_id => Event.find(params[:id]))
respond_to do |format|
if #guest.save
format.html { redirect_to root_path, notice: 'You are now assiting this event!' }
format.json { head :no_content}
else
format.html { redirect_to root_path, notice: "An error happened you can't assist this event" }
format.json { render json: #guest.errors, status: :unprocessable_entity }
end
end
end
This the current line to link the assist_event_path at events#index
<td><%= link_to 'Assist', assist_event_path(event), method: :put, data: { confirm: 'Do you want to assist to this event?' } %></td>
The result in the server log is passing both ids but the Guest object is not created:
Processing by EventsController#assist as HTML
Parameters: {"authenticity_token"=>"8nddKRZpYcgYDkfJIv/VXK8Os1FmW1oZ+zRIQUnLlE/dhgIA92chq++leqplfaB+bdqIZnCWlB0vPLRfuoHOGw==", "id"=>"1"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]]
↳ app/controllers/events_controller.rb:65:in `assist'
Event Load (0.2ms) SELECT "events".* FROM "events" WHERE "events"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/events_controller.rb:65:in `assist'
User model
class User < ApplicationRecord
has_many :events
has_many :guests
has_many :assisted_events, :through => :guests, :source => :event
end
Event model
class Event < ApplicationRecord
belongs_to :user
has_many :guests
has_many :assistances, :through => :guests, :source => :user
end
Guest model
class Guest < ApplicationRecord
belongs_to :user
belongs_to :event
end
routes file
Rails.application.routes.draw do
resources :events do
member do
patch :assist
put :assist
end
end
resources :users
root 'events#index'
end
EDIT ----
Events Controller
class EventsController < ApplicationController
before_action :set_event, only: [:show, :edit, :update, :destroy]
# GET /Events
# GET /Events.json
def index
#events = Event.all
end
# GET /Events/1
# GET /Events/1.json
def show
end
# GET /Events/new
def new
#event = User.find(session[:current_user_id]).events.build
end
# GET /Events/1/edit
def edit
end
# POST /Events
# POST /Events.json
def create
#event = User.find(session[:current_user_id]).events.build(event_params)
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
else
format.html { render :new }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /Events/1
# PATCH/PUT /Events/1.json
def update
respond_to do |format|
if #event.update(event_params)
format.html { redirect_to #event, notice: 'Event was successfully updated.' }
format.json { render :show, status: :ok, location: #event }
else
format.html { render :edit }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
# DELETE /Events/1
# DELETE /Events/1.json
def destroy
#event.destroy
respond_to do |format|
format.html { redirect_to events_url, notice: 'Event was successfully destroyed.' }
format.json { head :no_content }
end
end
def assist
#guest = Guest.create(:user_id => User.find(session[:current_user_id]), :event_id => Event.find(params[:id]))
respond_to do |format|
if #guest.save
format.html { redirect_to root_path, notice: 'You are now assiting this event!' }
format.json { head :no_content}
else
format.html { redirect_to root_path, notice: "An error happened you can't assist this event" }
format.json { render json: #guest.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_event
#event = Event.find(params[:id])
end
# Only allow a list of trusted parameters through.
def event_params
params.require(:event).permit(:title, :body)
end
end
Events#Index file
<p id="notice"><%= notice %></p>
<h1>Events</h1>
<% if session[:current_user_id].is_a? Integer %>
<h3>Current User ID: <%= session[:current_user_id] %></h3>
<% else %>
<%= link_to 'Create a new user', new_user_path %>
<% end %>
<table>
<thead>
<tr>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #events.each do |event| %>
<tr>
<td><%= event.title %></td>
<td><%= event.body %></td>
</tr>
<tr>
<td><%= link_to 'Show', event %></td>
<td><%= link_to 'Edit', edit_event_path(event) %></td>
<td><%= link_to 'Assist', assist_event_path(event), method: :put, data: { confirm: 'Do you want to assist to this event?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New event', new_event_path %>
Well this is kind of a guess since you didn't post any of your form except the link_to. I have no idea what variables you have passed to the events#index because you didn't post your controller code for that. That said you can pass any params you want with link_to.
edit OK, so it looks like user is in session[:current_user_id] so that is where the user id comes from...
latest edit to simplify
Add this route before your other routes to make sure it's at the top:
put '/assist' => 'events#assist'
Then in your form:
<td><%= link_to 'Assist', assist_path(event_id: event, user_id: session[:current_user_id]), method: :put, data: { confirm: 'Do you want to assist to this event?' } %></td>
Make sure your params are permitted in your strong parameters section.
# Only allow a list of trusted parameters through.
def event_params
params.require(:event).permit(:title, :body, :event_id, :user_id)
end
edit cleaning up your controller code:
def assist
#guest = Guest.new(:user_id => session[:current_user_id], :event_id => event_params[:id])
respond_to do |format|
if #guest.save
format.html { redirect_to root_path, notice: 'You are now assiting this event!' }
format.json { head :no_content}
else
format.html { redirect_to root_path, notice: "An error happened you can't assist this event" }
format.json { render json: #guest.errors, status: :unprocessable_entity }
end
end
end
You were passing the actual Event and User objects to create the #guest object. Also you were using the params, which means you weren't going through the event_params action. The purpose of the event_params action is to permit/deny so that someone can't submit params you don't want.

Save changes to tinymce inline editor in rails app?

I'm trying to save updates made in the inline tinymce editor in my rails app, but I don't know how to do it exactly as I want. I want the inline editor to be able to save while the view is 'html_safe'. I can save it fine if the form area is a text area (i.e. <div class="editor"><%= form.text_area :content %></div>), but I want to have the view in inline editor format so you can see your changes on the fly.
In the logs, it looks like the invitation params are closing before it's including the changes needed. How do I do this so that the inline editor changes are saved correctly?
Note: Everything else is working correctly, except the changes to the <%= #invitation.content %> are not being saved.
View:
<%= form_with(model: #invitation, local: true) do |form| %>
<%= form.hidden_field :event_id, value: #event.id %>
<div class="editor"><%= #invitation.content.html_safe %></div>
<script type="text/javascript">
tinyMCE.init({
selector: '.editor',
menubar: false,
inline: true,
plugins: "save",
toolbar: "save"
});
</script>
<% end %>
And my output from the log is:
Processing by InvitationsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2ssewH/CSN7is0P2LVrMkEmwZXcgmQqjWTjgrE6gGqAEv4dmLXFjEuOFJ9TRia+JF59SB6kKu5Le1xvt/FoxPg==", "invitation"=>{"event_id"=>"29"}, "mce_0"=>"<h1>Second Test Event CHANGEHERE!</h1>\r\n<h2>09/02/18 # 04:20</h2>\r\n<p> </p>\r\n<hr />\r\n<p>Bring Cheese</p>", "commit"=>"Update Invitation", "id"=>"7"}
Invitation Load (2.6ms) SELECT "invitations".* FROM "invitations" WHERE "invitations"."id" = $1 LIMIT $2 [["id", 7], ["LIMIT", 1]]
↳ app/controllers/invitations_controller.rb:66
(0.3ms) BEGIN
↳ app/controllers/invitations_controller.rb:43
Event Load (1.8ms) SELECT "events".* FROM "events" WHERE "events"."id" = $1 LIMIT $2 [["id", 29], ["LIMIT", 1]]
↳ app/controllers/invitations_controller.rb:43
(0.3ms) COMMIT
↳ app/controllers/invitations_controller.rb:43
Redirected to http://localhost:3000/events/29
And my controller is a basic object controller:
class InvitationsController < ApplicationController
before_action :set_invitation, only: [:show, :edit, :update, :destroy]
# GET /invitations
# GET /invitations.json
def index
#invitations = Invitation.all
end
# GET /invitations/1
# GET /invitations/1.json
def show
end
# GET /invitations/new
def new
#invitation = Invitation.new
end
# GET /invitations/1/edit
def edit
end
# POST /invitations
# POST /invitations.json
def create
#invitation = Invitation.new(invitation_params)
respond_to do |format|
if #invitation.save
format.html { redirect_to #invitation, notice: 'Invitation was successfully created.' }
format.json { render :show, status: :created, location: #invitation }
else
format.html { render :new }
format.json { render json: #invitation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /invitations/1
# PATCH/PUT /invitations/1.json
def update
respond_to do |format|
if #invitation.update(invitation_params)
format.html { redirect_to #invitation.event, notice: 'Invitation was successfully updated.' }
format.json { render :show, status: :ok, location: #invitation }
else
format.html { render :edit }
format.json { render json: #invitation.errors, status: :unprocessable_entity }
end
end
end
# DELETE /invitations/1
# DELETE /invitations/1.json
def destroy
#invitation.destroy
respond_to do |format|
format.html { redirect_to invitations_url, notice: 'Invitation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invitation
#invitation = Invitation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def invitation_params
params.require(:invitation).permit(:name, :content, :event_id)
end
end

Rails join table not saving

Hi I am playing around in rails and have built a little listing application.
My application has a listing model that has many tags through a has and belongs to many join table.
the join table is called listings_tags
The problem I have is that I cannot save the listing_tag association during create or update.
I can see in console
Started PATCH "/listings/92" for 127.0.0.1 at 2018-08-15 12:45:58 +1000
Processing by ListingsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"5isdLs2FiToZxtm1ZVPP0y0lKtnfyoLA8Njv4GBwWVH1M3TIm2IUW9ts5RR06OpQz8tgSBitZ7Rm69uVIifevQ==", "listing"=>{"name"=>"Canteen Coffee", "streetAddres"=>"19 Park Avenue", "suburb_id"=>"31", "post_code_id"=>"2", "region_id"=>"1", "country_id"=>"2", "telephone"=>"+61416650204", "url"=>"http://canteencoffee.com.au/canteen-kitchen/", "tag_ids"=>["", "1"]}, "commit"=>"Update Listing", "id"=>"92"}
Listing Load (0.2ms) SELECT "listings".* FROM "listings" WHERE "listings"."id" = $1 LIMIT $2 [["id", 92], ["LIMIT", 1]]
Unpermitted parameter: :tag_ids
(1.8ms) BEGIN
Suburb Load (5.4ms) SELECT "suburbs".* FROM "suburbs" WHERE "suburbs"."id" = $1 LIMIT $2 [["id", 31], ["LIMIT", 1]]
(1.7ms) COMMIT
Redirected to http://localhost:3000/listings/92
Completed 302 Found in 21ms (ActiveRecord: 9.0ms)
Obviously my issue is the :tag_ids
so I tried changing my listing params.require(:listing).permit() to include listing_attributes: [:id], tags: [:id] and :tag_ids
its killing me :) please help
Listing Model
class Listing < ApplicationRecord
has_and_belongs_to_many :tags
belongs_to :suburb
has_one :post_code, through: :suburb
accepts_nested_attributes_for :tags
def self.search(term)
if term
where('name LIKE ?', "%#{term}%")
else
order('id DESC')
end
end
end
Tag Model
class Tag < ApplicationRecord
has_and_belongs_to_many :listings
end
Listings Tags Schema
create_table "listings_tags", id: false, force: :cascade do |t|
t.bigint "listing_id", null: false
t.bigint "tag_id", null: false
t.index ["listing_id", "tag_id"], name: "index_listings_tags_on_listing_id_and_tag_id"
end
Listings Controller
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
# GET /listings
# GET /listings.json
def index
#listings = Listing.search(params[:term])
end
# GET /listings/1
# GET /listings/1.json
def show
#listing = Listing.find(params[:id])
#tags = #listing.tags
#suburb = #listing.suburb
#postcode = #suburb.post_code
end
# GET /listings/new
def new
#listing = Listing.new
end
# GET /listings/1/edit
def edit
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(listing_params)
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render :show, status: :created, location: #listing }
else
format.html { render :new }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /listings/1
# PATCH/PUT /listings/1.json
def update
respond_to do |format|
if #listing.update(listing_params)
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { render :show, status: :ok, location: #listing }
else
format.html { render :edit }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url, notice: 'Listing was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:name, :streetAddress, :telephone, :url, :term, :suburb_id, :post_code_id, :region_id, :country_id, :tag_ids)
end
end
Tags Controller
class TagsController < ApplicationController
before_action :set_tag, only: [:show, :edit, :update, :destroy]
# GET /tags
# GET /tags.json
def index
#tags = Tag.all
end
# GET /tags/1
# GET /tags/1.json
def show
#tag = Tag.find(params[:id])
#listings = #tag.listings
end
# GET /tags/new
def new
#tag = Tag.new
end
# GET /tags/1/edit
def edit
end
# POST /tags
# POST /tags.json
def create
#tag = Tag.new(tag_params)
respond_to do |format|
if #tag.save
format.html { redirect_to #tag, notice: 'Tag was successfully created.' }
format.json { render :show, status: :created, location: #tag }
else
format.html { render :new }
format.json { render json: #tag.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /tags/1
# PATCH/PUT /tags/1.json
def update
respond_to do |format|
if #tag.update(tag_params)
format.html { redirect_to #tag, notice: 'Tag was successfully updated.' }
format.json { render :show, status: :ok, location: #tag }
else
format.html { render :edit }
format.json { render json: #tag.errors, status: :unprocessable_entity }
end
end
end
# DELETE /tags/1
# DELETE /tags/1.json
def destroy
#tag.destroy
respond_to do |format|
format.html { redirect_to tags_url, notice: 'Tag was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_tag
#tag = Tag.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def tag_params
params.require(:tag).permit(:name)
end
end
Form
<%= bootstrap_form_for(#listing, local: true) do |form| %>
<%= form.text_field :name, id: :listing_name %>
<%= form.text_field :streetAddress, id: :listing_streetAddress %>
<%= form.collection_select(:suburb_id, Suburb.all, :id, :name) %>
<%= form.collection_select(:post_code_id, PostCode.all, :id, :number) %>
<%= form.collection_select(:region_id, Region.all, :id, :name) %>
<%= form.collection_select(:country_id, Country.all, :id, :name) %>
<%= form.text_field :telephone, id: :listing_telephone %>
<%= form.text_field :url, id: :listing_url %>
<%= form.select :tag_ids, Tag.all.pluck(:name, :id), {}, { multiple: true, class: "selectize" } %>
<%= form.submit %>
<% end %>
I really appreciate your help. I am sure it is probably something simple that I am doing wrong.
try this
params.require(:listing).permit(:name, :streetAddress, :telephone, :url, :term, :suburb_id, :post_code_id, :region_id, :country_id, :tag_ids => [])
source : https://github.com/rails/strong_parameters

What to do with error 'Please review the problems below:' using cocoon gem?

I am creating an ruby on rails 5 application. It is a todolist kind of application and using simple_form, haml-rails and cocoon gem. This is a application with nested form.
Generated a scaffold for goal and created model for action
Goal.rb and Action.rb
class Goal < ApplicationRecord
has_many :actions
accepts_nested_attributes_for :actions, reject_if: :all_blank
end
class Action < ApplicationRecord
belongs_to :goal
end
Then added the actions_attribute to permit in the params
class GoalsController < ApplicationController before_action :set_goal, only: [:show, :edit, :update, :destroy] def index
#goals = Goal.all end def show end def new
#goal = Goal.new end def edit end def create
#goal = Goal.new(goal_params)
respond_to do |format|
if #goal.save
format.html { redirect_to #goal, notice: 'Goal was successfully created.' }
format.json { render :show, status: :created, location: #goal }
else
format.html { render :new }
format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end end def update
respond_to do |format|
if #goal.update(goal_params)
format.html { redirect_to #goal, notice: 'Goal was successfully updated.' }
format.json { render :show, status: :ok, location: #goal }
else
format.html { render :edit }
format.json { render json: #goal.errors, status: :unprocessable_entity }
end
end end def destroy
#goal.destroy
respond_to do |format|
format.html { redirect_to goals_url, notice: 'Goal was successfully destroyed.' }
format.json { head :no_content }
end end private
def set_goal
#goal = Goal.find(params[:id])
end
def goal_params
params.require(:goal).permit(:name, :purpose, :deadline, actions_attributes: [:step])
end
end
Forms for both form.html and action.html
_form.html.haml
= simple_form_for(#goal) do |f|
= f.error_notification
.form-inputs
= f.input :name
= f.input :purpose
= f.input :deadline
%h3 Actions
#tasks
= f.simple_fields_for :actions do |action|
= render 'action_fields', f: action
.links
= link_to_add_association 'Add', f, :actions
.form-actions
= f.button :submit
// action.html.haml
.nested-fields
= f.input :step
= f.input :done, as: :boolean
= link_to_remove_association "remove task", f
log in the console when i submit form
Processing by GoalsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"jel0g+oCkNaspe7T9dz7suDczIOdoKJqPqPDK9ta0WLPbwaSPBwshrDD2BrNAFeLoDx+0/soe11MWaZaH8cQoA==", "goal"=>{"name"=>"ja", "purpose"=>"asdfd", "deadline"=>"asdfasd", "actions_attributes"=>{"0"=>{"step"=>"ARasd", "done"=>"1", "_destroy"=>"false"}, "1475080334356"=>{"step"=>"", "done"=>"0", "_destroy"=>"false"}}}, "commit"=>"Create Goal"}
Unpermitted parameter: _destroy
Unpermitted parameter: _destroy
(0.5ms) BEGIN
(0.5ms) ROLLBACK
Rendering goals/new.html.haml within layouts/application
Rendered goals/_action_fields.html.haml (18.5ms)
Rendered goals/_action_fields.html.haml (26.5ms)
Rendered goals/_action_fields.html.haml (19.0ms)
Rendered goals/_form.html.haml (252.5ms)
Rendered goals/new.html.haml within layouts/application (309.0ms)
Completed 200 OK in 932ms (Views: 898.5ms | ActiveRecord: 1.0ms)
The console log shows: Unpermitted parameter: done
This is because in your controller, only these parameters are permitted:
params.require(:goal).permit(:name, :purpose, :deadline, actions_attributes: [:step])

Posts Rating - Rails

I am implementing rating system in rails for posts.
On viewing a post one can rate the post by clicking radio button.
Below is the code. Consider only the post and rating don't consider tags, topics..
And there is no user in my concept one can rate whenever he needed and it should be added with existing rating of the post.
But, When I am doing this in log it shows the following:
Server log:
Started PATCH "/posts/34" for 127.0.0.1 at 2015-12-08 18:36:55 +0530
Processing by PostsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"l3aae99V424OyKVt5ULmqX2Mcs7DY2GYBskbLyhqqNENDn24ldCDAt4gNcgjESlFR6eaP0vcvrcoOerGE9lH5A==", "post"=>{"rating_ids"=>["5"]}, "commit"=>"Rate", "id"=>"34"}
Post Load (0.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1 [["id", 34]]
CACHE (0.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1 [["id", "34"]]
(0.0ms) begin transaction
SQL (4.0ms) INSERT INTO "ratings" ("star", "post_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["star", 5], ["post_id", 34], ["created_at", "2015-12-08 13:06:55.626133"], ["updated_at", "2015-12-08 13:06:55.626133"]]
(216.0ms) commit transaction
(0.0ms) begin transaction
Rating Load (1.0ms) SELECT "ratings".* FROM "ratings" WHERE "ratings"."id" = ? LIMIT 1 [["id", 5]]
Rating Load (0.0ms) SELECT "ratings".* FROM "ratings" WHERE "ratings"."post_id" = ? [["post_id", 34]]
SQL (2.0ms) UPDATE "ratings" SET "post_id" = NULL WHERE "ratings"."post_id" = ? AND "ratings"."id" IN (4, 25) [["post_id", 34]]
SQL (3.0ms) UPDATE "ratings" SET "post_id" = ?, "updated_at" = ? WHERE "ratings"."id" = ? [["post_id", 34], ["updated_at", "2015-12-08 13:06:55.878147"], ["id", 5]]
(170.0ms) commit transaction
Redirected to http://localhost:3000/topics/9
Completed 302 Found in 489ms (ActiveRecord: 397.0ms)
where it changes the post.id to NULL
SQL (2.0ms) UPDATE "ratings" SET "post_id" = NULL WHERE "ratings"."post_id" = ? AND "ratings"."id" IN (4, 25) [["post_id", 34]]
I don't know how this happens and how to overcome this So, Please help.
It changes the Rating database as below:
1st column: id, 2nd column: star, 3rd column: post_id
1,1,NULL
2,2,NULL
3,3,NULL
4,4,NULL
5,5,34
6,4,NULL
7,1,NULL
8,1,NULL
9,5,NULL
10,1,NULL
11,5,NULL
12,1,NULL
13,4,NULL
14,3,NULL
15,4,NULL
16,4,NULL
17,4,NULL
18,2,NULL
19,1,NULL
20,5,NULL
21,3,NULL
Post model:
class Post < ActiveRecord::Base
belongs_to :topic
has_many :comments
has_and_belongs_to_many :tags
has_many :ratings
end
Rating model:
class Rating < ActiveRecord::Base
belongs_to :post
end
Post show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #posts.name %> (
<%= #posts.topic.name %> )
</p>
<p>
<strong>Email:</strong>
<%= #posts.email %>
</p>
<p>
<strong>Message:</strong>
<%= #posts.message %>
</p>
<strong>Tags:</strong>
<% #posts.tags.each do |tag| %>
<div>
<%= tag.name %> <br>
</div>
<% end %>
<br>
<strong>Rating:</strong>
<%= #posts.ratings.group(:star).count %>
<%= form_for #posts do |f| %>
<% (1..5).each do |rating| %>
<%= radio_button_tag "post[rating_ids][]", rating %>
<%= rating %>
<% end %>
<%= f.submit('Rate') %>
<% end %>
<%= link_to 'Comments', post_comments_path(#posts) %>
<%= link_to 'Edit', edit_post_path(#posts) %> |
<%= link_to 'Back', topic_posts_url(#posts.topic) %>
Post controller:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
if params[:topic_id].to_i > 0
#topic = Topic.find(params[:topic_id])
#posts = #topic.posts.paginate(page: params[:page], per_page: 10)
else
#posts = Post.eager_load(:topic).paginate(page: params[:page], per_page: 10)
end
end
# GET /posts/1
# GET /posts/1.json
def show
#posts = Post.find(params[:id])
#tags = #posts.tags
#comment = Comment.new(:post => #posts)
end
# GET /posts/new
def new
#topic = Topic.find(params[:topic_id])
#posts = #topic.posts.new
end
# GET /posts/1/edit
def edit
#posts = Post.find(params[:id])
#tags = #posts.tags
end
# POST /posts
# POST /posts.json
def create
#topic = Topic.find(params[:topic_id])
#posts = #topic.posts.build(post_params)
respond_to do |format|
if #posts.save
format.html { redirect_to topic_url(#posts.topic_id), notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #posts }
else
format.html { render :new }
format.json { render json: #posts.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
#posts = Post.find(params[:id])
#tags = #posts.tags
respond_to do |format|
#posts.ratings.create(:star => params[:post][:rating_ids][0].to_i)
if #posts.update(post_params)
format.html { redirect_to topic_url(#posts.topic_id), notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #posts }
else
format.html { render :edit }
format.json { render json: #posts.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#posts.destroy
respond_to do |format|
format.html { redirect_to topic_url(#posts.topic_id), 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
#posts = 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(:name, :email, :message, :topic_id, {tag_ids:[]}, rating_ids:[])
end
end
I am new to rails and I need to implement this without using any gem..
Please help how it changes the post_id to NULL which I denoted in server log..
This is because after you created a Rating manually then goes #posts.update(rating_ids:[5]), which states that this post only should have rating with id 5, not 5 stars
Plus are you sure want your unauthenticated users to have access to post editing?
Since you save the rating before updating the post change your post_params to:
def post_params
params.require(:post).permit(:name, :email, :message, :topic_id, {tag_ids:[]})
end
As you are saving the rating from the params directly.
However you should consider changing your structure to use something like nested attributes which will automatically save/update ratings.

Resources