Ruby on rails trouble with nested form - ruby-on-rails

I have a clan.rb and clan_options.rb
clan.rb
class Clan < ActiveRecord::Base
has_one :options, :class_name => "ClanOptions", :foreign_key => "clan_id", dependent: :destroy
accepts_nested_attributes_for :options
end
clan_options.rb
class ClanOptions < ActiveRecord::Base
belongs_to :clan
end
To create an edit form for clan.rb and clan_options.rb I use the following in edit.html.erb:
<%= form_for #clan, :html => {:class => 'form-horizontal'} do |clan| %>
<fieldset>
<!-- Form stuff -->
<%= clan.fields_for :options do |o| %>
<!-- o.text_field -->
<% end %>
</fieldset>
<% end %>
I can update the fields of clan.rb but when I try to edit the value backgroundurl it won't save it. Backgroundurl is one of the clan_options.rb
clans_controller.rb
class ClansController < ApplicationController
before_filter :check_login, :only => [:new, :edit]
before_filter :check_bound, :only => [:new, :edit]
before_filter :check_clan, :only => :new
def update
#clan = Clan.find(params[:id])
if #clan.update_attributes(clan_update_params)
flash[:status] = TRUE
flash[:alert] = "Successfully updated your clan."
redirect_to clan_path(params[:id])
else
flash[:status] = FALSE
flash[:alert] = #clan.errors.full_messages
redirect_to edit_clan_path(#clan.id)
end
end
def edit
clan = Clan.where(id: params[:id])
if !clan.blank?
#clan = Clan.find(params[:id])
user = User.where(id: session[:user_id])
if !user.blank?
#De gebruiker is ingelogt en zit in de clan
#user = User.find(session[:user_id])
if #clan.id != #user.clan.id
flash[:status] = FALSE
flash[:alert] = 'That was not your clan, you may not edit theirs.'
redirect_to clans_path
elsif #user.clanmember.group.rank != 10
flash[:status] = FALSE
flash[:alert] = "You must be the leader to edit the clan."
redirect_to clan_path(#clan.id)
end
end
else
flash[:status] = FALSE
flash[:alert] = 'that clan doesn\'t exist or has been removed.'
redirect_to clans_path
end
end
def clan_params
params.require(:clan).permit(:name, :prefix, :description, :user_id)
end
def clan_update_params
params.require(:clan).permit(:name, :prefix, :description, :user_id, options: [:id, :clan_id, :backgroundurl])
end
end

I've fixed it by changing
def clan_update_params
params.require(:clan).permit(:name, :prefix, :description, :user_id, options: [:id, :clan_id, :backgroundurl])
end
to
def clan_update_params
params.require(:clan).permit(:name, :prefix, :description, :user_id, options_attributes: [:backgroundurl])
end

Related

Rails 5: given these three model associations...am I setting up my nested form field correctly?

Ok...am I doing this correctly? Am I setting up the nested form right given these model associations?
(should I include the volunteer_events controller and the volunteer_shift controller code here as well?)
volunteer_event model
class VolunteerEvent < ApplicationRecord
belongs_to :volunteer_default_event
validates_presence_of :date
has_many :volunteer_shifts, :dependent => :destroy
has_many :resources_volunteer_events, :dependent => :destroy
validates_associated :volunteer_shifts
def date_anchor
self.date.strftime('%Y%m%d')
end
# def date
# self.date
# end
def to_s
description
end
def time_range_s
return '0-0' if self.volunteer_shifts.length == 0
my_start_time = self.volunteer_shifts.sort_by(&:start_time).first.start_time
my_end_time = self.volunteer_shifts.sort_by(&:end_time).last.end_time
(my_start_time.strftime("%I:%M") + ' - ' + my_end_time.strftime("%I:%M")).gsub( ':00', '' ).gsub( ' 0', ' ').gsub( ' - ', '-' ).gsub(/^0/, "")
end
def merge_similar_shifts
hash = {}
self.volunteer_shifts.each{|y|
k = (y.volunteer_task_type_id.to_s || "0") + "-" + (y.description || "")
hash[k] ||= []
hash[k] << y
}
hash.each{|k, v|
prev_length = 0
length = v.length
while length != prev_length
v.each{|first|
v.each{|second|
next if first.id == second.id
combine = false
if ((first.end_time == second.start_time) or (first.start_time == second.end_time)) and (first.slot_number == second.slot_number)
first.start_time = [first.start_time, second.start_time].min
first.end_time = [first.end_time, second.end_time].max
combine = true
end
if combine
first.assignments << second.assignments
second.destroy
v.delete(second)
first.save!
break
end
}
}
prev_length = length
length = v.length
end
}
end
def copy_to(date, time_shift, copy_for)
new = self.class.new(self.attributes)
assigns = []
new.volunteer_shifts = self.volunteer_shifts.map{|x|
n = x.class.new(x.attributes); n.time_shift(time_shift);
if copy_for.include?(n.volunteer_task_type_id)
x.assignments.select{|x| x.contact_id && (!x.cancelled?)}.each do |y|
a = y.class.new(y.attributes)
a.time_shift(time_shift)
a.call_status_type_id = nil
a.attendance_type_id = nil
a.volunteer_shift = n
assigns << a
end
end
n
}
new.resources_volunteer_events = self.resources_volunteer_events.map{|x| x.class.new(x.attributes)}
new.date = date
new.resources_volunteer_events.each{|x| x.time_shift(time_shift)}
conflictors = assigns.select{|x| x.internal_date_hack_value = date; (!x.contact.nil?) && (!x.contact.is_organization) && x.find_overlappers(:for_contact).length > 0}
if conflictors.length == 0
new.save!
new.volunteer_shifts.each{|x| x.save!}
assigns.each{|x| x.save!}
return new
else
new.destroy if new.id
return conflictors
end
end
end
volunteer_shift model
class VolunteerShift < ApplicationRecord
validates_presence_of :roster_id
validates_presence_of :end_time
validates_presence_of :start_time
belongs_to :volunteer_default_shift
belongs_to :volunteer_task_type
has_many :assignments
belongs_to :program
belongs_to :roster
belongs_to :volunteer_event
has_many :contact_volunteer_task_type_counts, :primary_key => 'volunteer_task_type_id', :foreign_key => 'volunteer_task_type_id' #:through => :volunteer_task_type
...
end
assignment model
class Assignment < ApplicationRecord
attr_accessor :volunteer_shift #,:contact_id ???
belongs_to :volunteer_shift
has_one :volunteer_task_type, :through => :volunteer_shift, :source => :volunteer_task_type
belongs_to :contact ,optional: true
validates_presence_of :volunteer_shift
validates_associated :volunteer_shift
belongs_to :attendance_type
belongs_to :call_status_type
validates_presence_of :set_date, :if => :volshift_stuck
# validates_existence_of :contact, :allow_nil => true <----THIS IS BAD NEIBER
accepts_nested_attributes_for :volunteer_shift, allow_destroy: true
#fixme: Nodule::DelegationError -
# This error appears when trying to show the "Add New Assignment" model on the /assignments view
delegate :set_date, :set_date=, :to => :volunteer_shift
delegate :set_description, :set_description=, :to => :volunteer_shift
scope :date_range, lambda { |range|
joins(volunteer_shift: :volunteer_event)
.where(volunteer_shifts: { volunteer_events: { date: range } })
}
scope :is_after_today, lambda {||
{ :conditions => ['(SELECT date FROM volunteer_events WHERE id = (SELECT volunteer_event_id FROM volunteer_shifts WHERE id = assignments.volunteer_shift_id)) > ?', Date.today] }
}
scope :on_or_after_today, lambda {||
{ :conditions => ['(SELECT date FROM volunteer_events WHERE id = (SELECT volunteer_event_id FROM volunteer_shifts WHERE id = assignments.volunteer_shift_id)) >= ?', Date.today] }
}
scope :not_cancelled, -> { where('(attendance_type_id IS NULL OR attendance_type_id NOT IN (SELECT id FROM attendance_types WHERE cancelled = \'t\'))')}
scope :roster_is_limited_by_program, -> {where("roster_id IN (SELECT id FROM rosters WHERE limit_shift_signup_by_program = 't')").joins(:volunteer_shift)}
attr_accessor :attendance_type_id
...
end
assignments_controller
class AssignmentsController < ApplicationController
before_action :set_assignment, only: [:show, :edit, :update, :destroy]
skip_before_action :verify_authenticity_token #TODO refactor this line to be very specific
# GET /assignments or /assignments.json
def index
# #assignments = Assignment.limit(20)
# #assignments = Assignment.where(start: params[:start]..params[:end])
#assignments = Assignment.date_range(params[:start]..params[:end])
end
# GET /assignments/1 or /assignments/1.json
def show
end
# GET /assignments/new
def new
#assignment = Assignment.new
#fixme: build goes here
#assignment.volunteer_shift.build
#my_url = {:action => "create", :id => params[:id]}
end
# GET /assignments/1/edit
def edit
end
# POST /assignments or /assignments.json
def create
#assignment = Assignment.new(assignment_params)
respond_to do |format|
if #assignment.save
format.html { redirect_to #assignment, notice: "Assignment was successfully created." }
format.json { render :show, status: :created, location: #assignment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #assignment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /assignments/1 or /assignments/1.json
def update
#assignment.update(assignment_params)
end
# DELETE /assignments/1 or /assignments/1.json
def destroy
#assignment.destroy
# NOTE: comment original out 4 now
# respond_to do |format|
# format.html { redirect_to assignments_url, notice: "Assignment was successfully destroyed." }
# format.json { head :no_content }
# end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_assignment
#assignment = Assignment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def assignment_params
#fixme: ,volunteer_shift_attributes: [:???, :???, :???] <--- insert this below?
params.require(:assignment).permit(:title,
:redirect_to, :set_date, :date_range, :contact_id,
:start_time, :end_time, :start, :end, :attendance_type_id, :notes,
:call_status_type_id, :closed, :lock_version, :color,
volunteer_shift_attributes: [:volunteer_task_type_id,:roster_id,:program_id,:set_description,:set_date,:id,:destroy])
end
end
views/assignment/_form.html.erb
<%= form_for #assignment, :url => #my_url, remote: true do |f| %>
...
<%= f.fields_for :volunteer_shift do |builder| %>
<%= render 'volunteer_shift_fields', vs: builder %> <=====NESTED FORM THINGIE HERE...
<% end %>
...
<% end %>
_volunteer_shift_fields.html.erb <--- nested form partial
<div class="name large flex-row">
<%= vs.label :volunteer_shift %>
</div>
<div id="volunteer_shift" class="d-flex flex-row">
<div class="col-sm-12 p-2">
<div id="volunteer_shift" class="text-right">
<!-- old if: if class is assignment show volunteer shift else show default shift -->
<!-- we need default shift here...NO assignment is attached-->
<div class="field">
<%= vs.label :volunteer_task_type_id %>
<%= select_tag 'volunteer_task_type_id', options_from_collection_for_select([VolunteerTaskType.new(:description => ""), VolunteerTaskType.instantiables.effective_on(Date.today)].flatten, "id", "description") %>
</div>
<div class="field">
<%= vs.label :roster_id %>
<%= select_tag 'roster_id', options_from_collection_for_select([Roster.new(:name => ""), Roster.all].flatten, "id", "name") %>
</div>
<div class="field">
<%= vs.label :program_id %>
<%= select_tag 'program_id', options_from_collection_for_select([Program.new(:name => ""), Program.where(:volunteer => true)].flatten, "id", "name")%>
</div>
<div class="field">
<%= vs.label :set_description %>
<%= vs.text_field(:set_description, nil) %>
</div>
<div class="field">
<%= vs.label :set_date, "Date" %> <
<%= vs.text_field(:set_date, nil) %>
</div>
</div>
</div>
</div>

Rails nested form checkbox field not saving to my database model

I have a model association between two models Listing & Pricing. These are associated through Listing_Pricings model on a many to many basis.
If a listing is created the user can select through a check box field one of three pricing options which I intend to have saved in a seperate model Listing_Pricings. When a user selects the pricing option I can see it in the params hash but it fails to save in my database model.
Help please
My controller
class ListingsController < ApplicationController
protect_from_forgery except: [:upload_photo]
before_action :authenticate_user!, except: [:show]
before_action :set_listing, except: [:new, :create]
before_action :set_step, only: [:update, :edit]
before_action :is_authorised, only: [:edit, :update, :upload_photo, :delete_photo]
before_action :set_category, only: [:new, :edit, :show]
def new
#listing = current_user.listings.new
#listing.listing_pricings
#urgencies = Urgency.all
end
def create
#listing = current_user.listings.new listing_params
#listing.listing_pricings.first.listing_id = current_listing.id
if #listing.save
redirect_to edit_listing_path(#listing), notice: "Save..."
else
redirect_to request.referrer, flash: { error: #listing.errors.full_messages}
end
end
def edit
#urgencies = Urgency.all
#listing = Listing.find(params[:id])
#listing_category = #listing.category
#category_pricings = #listing_category.pricings.all
#listing_price = #listing.listing_pricings
end
def update
#listing = Listing.find(params[:id])
#listing_category = #listing.category
##category_pricings = #listing_category.pricings.all
##category = Category.find(params[:id])
#category_pricings = #listing_category.pricings.paginate(page: params[:page], per_page: 5)
#listing_pricing = #listing.listing_pricings
##listing_price = #listing_pricing.first.pricing
#listing_price = #listing.listing_pricings.build
#urgencies = Urgency.all
if #step == 2 && #listing.listing_pricings.each do |pricing|
if #listing.has_single_pricing && !pricing.bronze?
next;
else
if pricing[:listing_id].blank?
#|| pricing[:description].blank? || pricing[:complete_by_date].blank? || pricing[:price].blank?
return redirect_to request.referrer, flash: {error: "Invalid Pricing"}
end
end
end
end
if #step == 3 && listing_params[:description].blank?
return redirect_to request.referrer, flash: {error: "Description cannot be blank"}
end
if #step == 4 && #listing.photos.blank?
return redirect_to request.referrer, flash: {error: "You don't have any photos"}
end
if #step == 5
#listing_category_pricings.each do |pricing|
if #listing.has_single_pricing || !pricing.bronze? || !pricing.silver? || !pricing.gold? || !pricing.platinum?
next;
else
if pricing[:overview].blank? || pricing[:description].blank? || pricing[:complete_by_date].blank? || pricing[:price].blank?
return redirect_to edit_listing_path(#listing, step: 2), flash: {error: "Invalid pricing"}
end
end
end
if #listing.description.blank?
return redirect_to edit_listing_path(#listing, step: 3), flash: {error: "Description cannot be blank"}
elsif #listing.photos.blank?
return redirect_to edit_listing_path(#listing, step: 4), flash: {error: "You don't have any photos"}
end
end
if #listing.update(listing_params)
flash[:notice] = "Saved..."
else
return redirect_to request.referrer, flash: {error: #listing.errors.full_messages}
end
if #step < 5
redirect_to edit_listing_path(#listing, step: #step + 1)
else
redirect_to users_dashboard_path
end
end
def show
#listing = Listing.find(params[:id])
#listing_category = #listing.category
#listing_category_pricings = #listing_category.pricings.all
#urgencies = Urgency.all
end
def upload_photo
#listing.photos.attach(params[:file])
render json: { success: true}
end
def delete_photo
#image = ActiveStorage::Attachment.find(params[:photo_id])
#image.purge
redirect_to edit_listing_path(#listing, step: 4)
end
def set_pricing_id
Listing.update_all({pricing_id: true}, {id: params[:listing_id]} )
end
private
def set_step
#step = params[:step].to_i > 0 ? params[:step].to_i : 1
if #step > 5
#step = 5
end
end
def set_category
#categories = Category.all
end
def set_listing
#listing = Listing.find(params[:id])
end
def is_authorised
redirect_to root_path, alert: "You do not have permission" unless current_user.id == #listing.user_id
end
def listing_params
params.require(:listing).permit(:title, :video, :description, :active, :category_id, :budget, :urgency_id, :has_single_pricing,:pricing_id)
end
def category_params
params.require(:category).permit(:name)
end
end
Listing.rb
class Listing < ApplicationRecord
belongs_to :user
belongs_to :category
belongs_to :urgency
has_many :listing_pricings, dependent: :destroy
has_many :pricings, through: :listing_pricings
has_many_attached :photos
has_rich_text :description
validates :title, presence: { message: 'cannot be blank' }
#has_many :pricings
#accepts_nested_attributes_for :pricings
#has_many :listing_categories
end
Pricings.rb
class Pricing < ApplicationRecord
belongs_to :category, optional: false
has_many :listing_pricings
has_many :listings, through: :listing_pricings
enum pricing_type: [:bronze, :silver, :gold, :platinum]
end
ListingPricing.rb
class ListingPricing < ApplicationRecord
belongs_to :listing, optional: true, dependent: :destroy
belongs_to :pricing, optional: true, dependent: :destroy
end
My View
<div class="step-content <%= 'is-active' if #step == 2 %>">
<div class="field">
<div class="control">
<div class="tile is-ancestor">
<% #category_pricings.each do |cp| %>
<div class="tile is-parent">
<article class="tile is-child box">
<div class="subtitle"><%= "#{cp.overview}" %></div>
<div class="content"><%= "Deposit payable: £#{cp.price}" %></div>
<div class="content"><%= "Time to complete: #{pluralize(cp.complete_by_date, 'Day')}" %></div>
<tr valign="bottom"><div class="content"><%= "#{cp.description}" %></div></tr>
<tr valign="bottom"><div class="content"><%= "#{cp.id}" %></div></tr>
<%= f.fields_for :listing_pricings do |lp| %>
<%= hidden_field_tag "pricing_id[]", cp.id %>
<div class="form-group">
<%= lp.check_box_tag :pricing_id, cp.id %>
</div>
<% end %>
</article>
</div>
<% end %>
</div>
</div>
</div>
</div>
My error trace says
PG::NotNullViolation: ERROR: null value in column "pricing_id" violates not-null constraint DETAIL: Failing row contains (16, 2, null, 2019-12-13 17:51:50.722906, 2019-12-13 17:51:50.722906).
Any thoughts guys ?
Parameters:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"tOnX6Q5YjHgXn3Xk5Wh2NioPfLrziiPVwyHkLF8BBFOjuWHdM1w8A7AdGpHdFGR3n+zlFsN2B/3IOMenXU1daA==",
"step"=>"2",
"listing"=>{"title"=>"Please clean my home", "category_id"=>"3", "urgency_id"=>"10", "has_single_pricing"=>"0", "description"=>"<div>This is my second listing </div>", "video"=>""},
"pricing_id"=>"1",
"commit"=>"Save & Continue",
"id"=>"2"}
I do this for one of my project. I replace my models with Pricing, Listing and ListPricing for you.
In your model, you have to have dependent: :destroy on has_many ... through relationship (otherwise, unchecking checkbox will not work).
# app/model/listing.rb
class Listing < ApplicationRecord
has_many :listing_pricings
has_many :pricings, through: :listing_pricings, dependent: :destroy
# your code
end
In your view,
- Pricing.all.each do |p|
= f.check_box :pricing_ids, { multiple: true }, p.id, false
= f.label :pricing_id, p.something
end
In listing controller, make sure you permit :pricing_ids in listing controller
# app/controllers/listings_controller.rb
def listing_param
params.require(:listing).permit(
# other params you permit,
pricing_ids: []
)
end

simple_form not showing nested field

I am trying simple_form nested attributes as suggested in https://github.com/plataformatec/simple_form/wiki/Nested-Models
The thing is, when I render the form I just can see the submit button, but not the input field. What am I doing wrong?
_form.html.erb
<%= simple_form_for [:admin, #incident] do |f| %>
<%= f.error_notification %>
<%= f.simple_fields_for :comments do |builder| %>
<%= builder.input :info, label: "Informe de seguimiento" %>
<% end %>
<div class="form-actions">
<%= f.submit "Enviar", class: "btn btn-primary" %>
</div>
<% end %>
incidents_controller.rb
class Admin::IncidentsController < ApplicationController
before_action :set_incident, only: [:show, :edit, :update]
def index
#incidents = Incident.all
end
def show
end
def new
#incident = Incident.new
#incident.comments.build
end
def edit
end
def update
respond_to do |format|
if #incident.update(incident_params)
format.html { redirect_to #incident, notice: 'Incidencia actualizada actualizada con éxito.' }
format.json { render :show, status: :ok, location: #incident }
else
format.html { render :edit }
format.json { render json: #incident.errors, status: :unprocessable_entity }
end
end
end
private
def set_incident
#incident = Incident.find(params[:id])
end
def incident_params
params.require(:incident).permit(:info, :subject, :status, comments_attributes: [:info])
end
end
incident.rb
class Incident < ApplicationRecord
belongs_to :user, optional: true
has_many :comments, dependent: :destroy
accepts_nested_attributes_for :comments, allow_destroy: true, reject_if: proc { |attributes| attributes['info'].blank? }
enum status: [:abierto, :tramite, :pendiente, :cerrado]
after_initialize :set_default_status, :if => :new_record?
def set_default_status
self.status ||= :abierto
end
end
comment.rb
class Comment < ApplicationRecord
belongs_to :user, optional: true
belongs_to :incident
end
You need to add #incident.comments.build to the show action of Admin::IncidentsController. Now it has no comments, I suppose, so the form is empty.
And you need to add :id to comments_attributes, without it comment can't be saved. If you planning to have some 'Delete' checkbox for existing comments you also need to add :_destroy to the attributes array

Ruby on Rails: :topic_id=>nil, I'm lost

So I am working on an assignment at the moment, where I am trying to display favorited posts. I currently have the favorited post displayed, but when I click it, it doesn't doesn't redirect me to anywhere.
Here is the code I currently have:
User#show where I am currently trying to display the favorited posts:
<div class="row">
<div class="col-md-8">
<div class="media">
<br />
<% avatar_url = #user.avatar_url(128) %>
<% if avatar_url %>
<div class="media-left">
<%= image_tag avatar_url, class: 'media-object' %>
</div>
<% end %>
<div class="media-body">
<h2 class="media-heading"><%= #user.name %></h2>
<small>
<%= pluralize(#user.posts.count, 'post') %>,
<%= pluralize(#user.comments.count, 'comment') %>
</small>
</div>
</div>
</div>
</div>
<h2>Posts</h2>
<%= posts_exists? %>
<%= render #user.posts %>
<h2>Comments</h2>
<%= comments_exists? %>
<%= render #user.comments %>
<h2>Favorites</h2>
<% #posts.each do |post| %>
<%= render partial: 'votes/voter', locals: { post: post } %>
<%= link_to post.title, topic_post_path(#topic, post) %>
<%= image_tag current_user.avatar_url(48), class: "gravatar" %>
<%= post.comments.count %> Comments
<% end %>
The error is occuring on the following line:
<%= link_to post.title, topic_post_path(#topic, post) %>
Here is the output from the error:
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"posts", :id=>"54", :topic_id=>nil} missing required keys: [:topic_id]):
29: <h2>Favorites</h2>
30: <% #posts.each do |post| %>
31: <%= render partial: 'votes/voter', locals: { post: post } %>
32: <%= link_to post.title, topic_post_path(#topic, post) %>
33: <%= image_tag current_user.avatar_url(48), class: "gravatar" %>
34: <%= post.comments.count %> Comments
35: <% end %>
app/views/users/show.html.erb:32:in `block in _app_views_users_show_html_erb__1919900632491741904_70127642538380'
app/views/users/show.html.erb:30:in `_app_views_users_show_html_erb__1919900632491741904_70127642538380'
Obviously Topid.id is nil, but I can't figure out why. I'm going to provide you with everything I think you could need? I know this is probably a simple nooby issue, but I've been stuck on it for nearly an entire day already.
Here is my User#Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new
#user.name = params[:user][:name]
#user.email = params[:user][:email]
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][:password_confirmation]
if #user.save
flash[:notice] = "Welcome to Bloccit #{#user.name}!"
create_session(#user)
redirect_to root_path
else
flash[:error] = "There was an error creating your account. Please try again."
render :new
end
end
def show
#user = User.find(params[:id])
#posts = #user.posts.visible_to(current_user)
#posts = Post.joins(:favorites).where('favorites.user_id = ?', #user.id)
#favorites = current_user.favorites
end
end
Here is my Post#Controller:
class PostsController < ApplicationController
before_action :require_sign_in, except: :show
before_action :authorize_user, except: [:show, :new, :create]
def show
#post = Post.find(params[:id])
end
def new
#topic = Topic.find(params[:topic_id])
#post = Post.new
end
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.build(post_params)
#post.user = current_user
if #post.save
#post.labels = Label.update_labels(params[:post][:labels])
flash[:notice] = "Post was saved."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :new
end
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
#post.assign_attributes(post_params)
if #post.save
#post.labels = Label.update_labels(params[:post][:labels])
flash[:notice] = "Post was updated."
redirect_to [#post.topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :edit
end
end
def destroy
#post = Post.find(params[:id])
if #post.destroy
flash[:notice] = "\"#{#post.title}\" was deleted successfully."
redirect_to #post.topic
else
flash[:error] = "There was an error deleting the post."
render :show
end
end
private
def post_params
params.require(:post).permit(:title, :body)
end
def authorize_user
post = Post.find(params[:id])
unless current_user == post.user || current_user.admin?
flash[:error] = "You must be an admin to do that."
redirect_to [post.topic, post]
end
end
end
Here is my Topics#Controller:
class TopicsController < ApplicationController
before_action :require_sign_in, except: [:index, :show]
before_action :authorize_user, except: [:index, :show]
def index
#topics = Topic.all
end
def show
#topic = Topic.find(params[:id])
end
def new
#topic = Topic.new
end
def create
#topic = Topic.new(topic_params)
if #topic.save
#topic.labels = Label.update_labels(params[:topic][:labels])
redirect_to #topic, notice: "Topic was saved successfully."
else
flash[:error] = "Error creating topic. Please try again."
render :new
end
end
def edit
#topic = Topic.find(params[:id])
end
def update
#topic = Topic.find(params[:id])
#topic.assign_attributes(topic_params)
if #topic.save
#topic.labels = Label.update_labels(params[:topic][:labels])
flash[:notice] = "Topic was updated."
redirect_to #topic
else
flash[:error] = "Error saving topic. Please try again."
render :edit
end
end
def destroy
#topic = Topic.find(params[:id])
if #topic.destroy
flash[:notice] = "\"#{#topic.name}\" was deleted successfully."
redirect_to action: :index
else
flash[:error] = "There was an error deleting the topic."
render :show
end
end
private
def topic_params
params.require(:topic).permit(:name, :description, :public)
end
def authorize_user
unless current_user.admin?
flash[:error] = "You must be an admin to do that."
redirect_to topics_path
end
end
end
Here is my User Model:
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :votes, dependent: :destroy
has_many :favorites, dependent: :destroy
before_save { self.email = email.downcase }
before_save { self.role ||= :member }
EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, length: { minimum: 1, maximum: 100 }, presence: true
validates :password, presence: true, length: { minimum: 6 }, if: "password_digest.nil?"
validates :password, length: { minimum: 6 }, allow_blank: true
validates :email,
presence: true,
uniqueness: { case_sensitive: false },
length: { minimum: 3, maximum: 100 },
format: { with: EMAIL_REGEX }
has_secure_password
enum role: [:member, :admin]
def favorite_for(post)
favorites.where(post_id: post.id).first
end
def avatar_url(size)
gravatar_id = Digest::MD5::hexdigest(self.email).downcase
"http://gravatar.com/avatar/#{gravatar_id}.png?s=#{size}"
end
end
Here is my Topic Model:
class Topic < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :labelings, as: :labelable
has_many :labels, through: :labelings
end
Here is my Post Model:
class Post < ActiveRecord::Base
belongs_to :topic
belongs_to :user
has_many :comments, dependent: :destroy
has_many :votes, dependent: :destroy
has_many :labelings, as: :labelable
has_many :labels, through: :labelings
has_many :favorites, dependent: :destroy
default_scope { order('rank DESC') }
scope :visible_to, -> (user) { user ? all : joins(:topic).where('topics.public' => true) }
validates :title, length: { minimum: 5 }, presence: true
validates :body, length: { minimum: 20 }, presence: true
validates :topic, presence: true
validates :user, presence: true
def up_votes
votes.where(value: 1).count
end
def down_votes
votes.where(value: -1).count
end
def points
votes.sum(:value)
end
def update_rank
age_in_days = (created_at - Time.new(1970,1,1)) / 1.day.seconds
new_rank = points + age_in_days
update_attribute(:rank, new_rank)
end
end
Any insight anyone could provide, I would be extremely grateful for. If you have the time to explain where I went wrong as well, that would be even more helpful.
User#show where I am currently trying to display the favorited posts
But you're not setting #topic in your User#show action. That's why it's nil.
def show
#user = User.find(params[:id])
#posts = #user.posts.visible_to(current_user)
#posts = Post.joins(:favorites).where('favorites.user_id = ?', #user.id)
#favorites = current_user.favorites
# your #topic object is not in here?
end
Since a post belongs_to a topic you could do something like this:
<%= link_to post.title, topic_post_path(post.topic, post) %>

Dont display fields nested attributes with using gem cocoon

i have model poll with nested attributes poll_items:
class Poll < ActiveRecord::Base
ITEMS_COUNT_MAX = 5
attr_accessible :from_date, :question, :results_hidden, :to_date, :owner_id, :poll_items_attributes
belongs_to :owner, polymorphic: true
has_many :poll_items, dependent: :destroy
has_many :poll_votes, through: :poll_items
accepts_nested_attributes_for :poll_items, allow_destroy: true,
reject_if: proc { |attributes| attributes['answer'].blank? }
#validates :owner, :question, :from_date, :to_date, presence: true
#validate :validate_duplicate, on: :create
validate :validate_max_poll_items, on: :update
after_initialize :defaults
...................................................................
model pollItem
attr_accessible :answer
attr_readonly :poll_votes_count
belongs_to :poll
has_many :poll_votes, dependent: :destroy
has_many :users, through: :poll_votes
validates :poll, :answer, presence: true
validate :validate_duplicate, on: :create
scope :editable, lambda { |u|
unless u.moderator?
where(:poll.owner.user_id => u.id).where(:created_at.gt Settings.edit_delay.minutes.ago)
end
}
private
def validate_duplicate
errors.add(:base, :duplicate) unless poll.poll_items.where(answer: answer).empty?
end
end
Poll_controller:
class PollsController < ApplicationController
before_filter :authenticate_user!
before_filter :set_poll, only: [:show, :edit, :update, :destroy]
before_filter :find_owner, only: [:new, :create]
def new
#poll = Poll.new
end
def create
#poll = Poll.new params[poll_params]
##poll.owner = #owner
respond_to do |format|
if #poll.save
format.html { redirect_to [:edit, #poll], notice: 'Опрос был успешно создан.' }
else
format.html { render :new }
end
end
end
def show
end
def edit
#poll.poll_items.build
end
def update
if #poll.editable?(current_user)
if #poll.update_attributes params[:poll]
respond_to do |format|
format.html { redirect_to [:edit, #poll], notice: 'Опрос был успешно обновлен.' }
end
else
respond_to do |format|
format.html { render :edit, alert: #poll.errors }
end
end
end
end
def destroy
#poll.destroy
respond_to do |format|
format.html { redirect_to #owner, notice: 'Опрос был успешно удален.' }
end
end
private
def poll_params
params.require(:poll).permit(:from_date, :question, :results_hidden, :to_date,
:owner_id, poll_items_attributes: [:id, :unswer, :_destroy])
end
protected
def set_poll
#poll = Poll.find(params[:id])
#owner = #poll.owner
end
def find_owner
#owner = case
when params[:post_id]
Post.visible(current_user).find(params[:post_id])
when params[:blog_post_id]
BlogPost.with_privacy(current_user).find(params[:blog_post_id])
end
end
end
I installed gem cocoon:
next i create view new.html.haml:
%h1= title "Новый опрос"
= simple_form_for #poll do |f|
= f.error_messages header_message: nil
= f.input :question, disabled: !#poll.editable?(current_user), input_html: { class: 'input-block-level' }
= f.input :results_hidden, as: :boolean, inline_label: 'Скрыть результаты до окончания опроса', label: false
= f.input :from_date, as: :datetime, input_html: { class: 'poll_date' }
= f.input :to_date, as: :datetime, input_html: { class: 'poll_date' }
.items-index
%h3#poll-items Варианты ответа (не больше пяти)
= f.simple_fields_for :poll_items do |poll|
= render 'poll_items_fields', f: poll
= link_to_add_association 'Добавить еще вариант', f, :poll_items
.form-actions
= f.button :submit, 'Опубликовать опрос', class: 'btn-bg'
%p
Вернуться к посту:
= link_to #owner
poll_items_fields.html.haml:
.poll_row
.poll_item
= f.input :answer, input_html: { class: 'ctrlenter expanding' }, label: false, placeholder: 'Введите вариант ответа'
= link_to_remove_association "удалить", f
I open page new for creating new poll, but only field for new name quation poll and button "create poll". No fields for adding poll_items. I thinkm dont render form poll_items_fields.html.haml. But why? How fix?
If I understood correctly, your new method should look like this
def new
#poll = Poll.new
#poll.poll_items.build
end
And also you have unswer instead of answer in poll_items_attributes, so fix that too.
def poll_params
params.require(:poll).permit(:from_date, :question, :results_hidden, :to_date, :owner_id, poll_items_attributes: [:id, :answer, :_destroy])
end
Update:
You should also remove attr_accessible :from_date, :question, :results_hidden, :to_date, :owner_id, :poll_items_attributes from your Poll model as Rails 4 uses strong parameters.
And also this line #poll = Poll.new params[poll_params] in create method should look like this #poll = Poll.new(poll_params)

Resources