Why do I get "NameError in Discussions"? - ruby-on-rails

I'm currently working on a Ruby on Rails application that involves users creating discussions and commenting with microposts. It's a pretty simple concept but I'm new and have run into some trouble.
When trying to look at the discussions page (index of discussion) I get the error "NameError in Discussions#index":
undefined local variable or method `discussion' for #<#<Class:0x00000100c6e020>:0x0000010380edd8>
This is my Discussion controller:
class DiscussionsController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update]
def show
#user = User.find(params[:id])
#discussions = #user.discussion.paginate(page: params[:page])
#microposts = #user.micropost.paginate(page: params[:page])
end
def index
#discussions = Discussion.all
end
def create
#discussion = current_user.discussions.build(params[:discussion])
if #discussion.save
flash[:success] = "Discussion Started!"
redirect_to root_url
else
render 'static_pages/home'
end
end
def destroy
end
def edit
end
def update
end
def new
end
end
This is my Micropost form:
<% #micropost = Micropost.new %>
<% #micropost.discussion_id = discussion.id %>
<%= form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
</div>
<%= f.hidden_field :discussion_id, discussion.id%>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
This is my Discussion partial:
<% content_for :script do %>
<%= javascript_include_tag 'hover_content' %>
<% end %>
<li>
<div class = "intro-bar"><span class = "intro"><%=discussion.intro %></span></div>
<div class = "content-bar">
<span class = "content"><%= discussion.content %></span>
<div class = "buttons">
<div class = "vote-neg"><%= link_to "Break Up", signup_path,class: "btn btn-large btn-breakup" %></div>
<div class = "vote-plus"><%= link_to "Stay Together", signup_path,class: "btn btn-large btn-staytogether" %></div>
</div>
</div>
</li>
<span class = "timestamp">
Posted <%= time_ago_in_words(discussion.created_at) %> ago.
</span>
<div class = "comments">
<% discussion.microposts.each do |micropost| %>
<li>
<div class = "post-comment"><%= micropost.content%></div>
</li>
<% end %>
</div>
<% if signed_in? %>
<div class = "row">
<aside class = "span4">
<section>
<%= render 'shared/micropost_form', :locals => {:discussion => discussion }%>
</section>
</aside>
</div>
<% end %>
This is my Micropost controller:
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
def index
end
def create
#discussion = current_user.discussions.new
#micropost = current_user.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Posted!"
redirect_to root_url
else
render 'static_pages/home'
end
end
def destroy
end
end
This is my Discussion model:
class Discussion < ActiveRecord::Base
attr_accessible :content, :intro
has_many :microposts, dependent: :destroy
belongs_to :user
validates :content, presence: true, length: { maximum: 600 }
validates :intro, presence: true
default_scope order: 'discussions.created_at DESC'
end
This is my User model:
class User < ActiveRecord::Base
attr_accessible :email, :username, :age, :sex, :points, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
has_many :discussions, dependent: :destroy
before_save {|user| user.email = email.downcase}
before_save :create_remember_token
validates :username, presence: true, length: {maximum: 15}
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
validates :age, presence: true
validates :sex, presence: true
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
This is my Discussion index:
<% provide(:title, "Discussions") %>
<h1>Discussions</h1>
<ul class = "discussions">
<% #discussions.each do |discussion| %>
<li>
<%= render :partial =>"discussions/discussion", :locals=>{:discussion=>discussion} %>
</li>
<% end %>
</ul>

Try rewriting this line:
<%= render 'shared/micropost_form', :locals => {:discussion => discussion }%>
as:
<%= render 'shared/micropost_form', :discussion => discussion %>

Related

Data not persisted between steps in wizard

I have followed Nicolas Blanco's tutorial to make a "goal" wizard for my app.
There are two steps in the wizard. The first consisting of the form fields "name", "description" and "plan", the second has "deadline", which is a datetimepicker, "reporting frequency" and "days missed tolerance".
It seems to work when I click continue in the first step, but on clicking finish in the second step, the object #goal_wizard doesn't seem to include the parameters from the first step.
My goal.rb:
module Wizard
module Goal
STEPS = %w(step1 step2).freeze
class Base
include ActiveModel::Model
attr_accessor :goal
delegate *::Goal.attribute_names.map { |attr| [attr, "#{attr}="] }.flatten, to: :goal
def initialize(goal_attributes)
#goal = ::Goal.new(goal)
end
end
class Step1 < Base
validates :name, presence: true, length: { maximum: 50 }
validates :description, presence: true, length: { maximum: 300 }
validates :plan, presence: true, length: { maximum: 1000 }
end
class Step2 < Step1
validates :reporting_frequency, presence: true,
numericality: { greater_than_or_equal_to: 0 }
validates :days_missed_tolerance, presence: true,
numericality: { greater_than_or_equal_to: 0}
validates :deadline, presence: true
end
end
end
wizards_controller.rb:
class WizardsController < ApplicationController
before_action :load_goal_wizard, except: :validate_step
def validate_step
current_step = params[:current_step]
#goal_wizard = wizard_goal_for_step(current_step)
#goal_wizard.goal.attributes = goal_wizard_params
session[:goal_attributes] = #goal_wizard.goal.attributes
if #goal_wizard.valid?
next_step = wizard_goal_next_step(current_step)
create and return unless next_step
redirect_to action: next_step
else
render current_step
end
end
def create
# #user = current_user
# #goal = #user.goals.new(#goal_wizard.goal)
if #goal_wizard.goal.save
session[:goal_attributes] = nil
redirect_to root_path, notice: 'Goal succesfully created!'
else
redirect_to({ action: Wizard::Goal::STEPS.first }, alert: 'There were a problem creating the goal.')
end
end
private
def load_goal_wizard
#goal_wizard = wizard_goal_for_step(action_name)
end
def wizard_goal_next_step(step)
Wizard::Goal::STEPS[Wizard::Goal::STEPS.index(step) + 1]
end
def wizard_goal_for_step(step)
raise InvalidStep unless step.in?(Wizard::Goal::STEPS)
"Wizard::Goal::#{step.camelize}".constantize.new(session[:goal_attributes])
end
def goal_wizard_params
params.require(:goal_wizard).permit(:name, :description, :plan, :deadline, :reporting_frequency, :days_missed_tolerance)
end
class InvalidStep < StandardError; end
end
step1.html.erb:
<ol class="breadcrumb">
<li class='active'>Step 1</li>
<li>Step 2</li>
</ol>
<%= form_for #goal_wizard, as: :goal_wizard, url: validate_step_wizard_path do |f| %>
<%= render "error_messages" %>
<%= hidden_field_tag :current_step, 'step1' %>
<%= f.label :name %>
<%= f.text_field :name, class: "form_control" %>
<%= f.label :description %>
<%= f.text_field :description, class: "form_control" %>
<%= f.label :plan %>
<%= f.text_field :plan, class: "form_control" %>
<%= f.submit 'Continue', class: "btn btn-primary" %>
<% end %>
step2.html.erb:
<ol class="breadcrumb">
<li><%= link_to "Step 1", step1_wizard_path %></li>
<li class="active">Step 2</li>
</ol>
<%= form_for #goal_wizard, as: :goal_wizard, url: validate_step_wizard_path do |f| %>
<%= render "error_messages" %>
<%= hidden_field_tag :current_step, 'step2' %>
<%= f.label :deadline %>
<div class='input-group date' id='datetimepicker1'>
<%= f.text_field :deadline, class: "form-control" %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<%= f.label "How often do I want to report? (1 = every day)" %>
<%= f.number_field :reporting_frequency, class: "form_control" %>
<%= f.label "How many times can I miss my report?" %>
<%= f.number_field :days_missed_tolerance, class: "form_control" %>
<script type="text/javascript">
$(function () {
$('#datetimepicker1').datetimepicker({
minDate:new Date()
});
});
</script>
<%= f.submit "Finish", class: "btn btn-primary" %>
<% end %>
Over here you're passing the goal_attributes to initialize, but you're never using them.
def initialize(goal_attributes)
#goal = ::Goal.new(goal)
end
If you look at Nicolas Blanco's code he doesn't make that mistake.

Rails 5 - n+1 query issue inside simple_form gem

I'm trying to resolve every n+1 issue with Bullet gem in my Rails, but I can't figure out this particular problem:
_form.html.erb
<%= simple_form_for([:admin, #course, #lesson]) do |f| %>
<div class="form-inputs">
<div class="col-md-6">
<%= f.input :start_at, minute_step: 5, start_year: Date.today.year %>
</div>
<div class="col-md-6">
<%= f.input :end_at, minute_step: 5, start_year: Date.today.year %>
</div>
<div class="col-md-6">
<!--Here is the problem-->
<%= f.association :room, :label_method => lambda { |room| "#{room.title} (#{room.building.title})"}%>
<!--Here is the problem-->
</div>
<div class="col-md-6">
<%= f.association :teacher, :label_method => lambda { |teacher| "#{teacher.first_name} #{teacher.last_name}"},
collection: #course.teachers%>
</div>
</div>
<div class="col-md-12">
<div class="form-actions text-center">
<%= f.submit class: "btn btn-primary btn-lg" %>
</div>
</div>
<% end %>
Form is rendered to new.html.erb and edit.html.erb. Problem occurs on line with room association where I'm trying to get room.building.title.
Here's the screenshoot:
As you can see, I only want to display room name with its centre name, but Bullet throws an error. Problem is that I'm using that lambda function so creating a variable in a controller doesn't help (or at least I don't know how to create it properly) since problem occurs inside select box.
Here I'm including my controller:
lessons_controller.rb
module Admin
class LessonsController < Admin::AdminController
helper_method :convert_time, :convert_day
before_action :set_course
before_action :set_lesson, only: [:show, :edit, :update, :destroy]
def index
#lessons = Lesson.includes(:teacher,:course, :room => :building).where(course_id: #course).paginate(page: params[:page], per_page: 10)
# #course_lessons = #course.lessons.paginate(page: params[:page], per_page: 10)
end
def new
##room = Room.all.includes(:building)
#lesson = Lesson.new
end
def create
#lesson = Lesson.new(lesson_params)
#lesson.course = #course
if #lesson.save
flash[:success] = "Lesson was created"
redirect_to admin_course_lessons_path(#course)
else
render 'new'
end
end
def edit
end
def update
if #lesson.update(lesson_params)
flash[:success] = "Lesson was updated"
redirect_to admin_course_lessons_path(#course)
else
render 'edit'
end
end
def show
end
def destroy
#lesson.destroy
flash[:danger] = "Lesson was deleted"
redirect_to admin_course_lessons_path(#course)
end
private
def set_course
#course = Course.find(params[:course_id])
end
def set_lesson
#lesson = Lesson.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:start_at,:end_at, :room_id, :teacher_id)
end
end
end
(Actions relevant for us in this situation are new and edit)
Here are the relevant models:
room.rb
class Room < ApplicationRecord
belongs_to :building
has_many :lessons, dependent: :destroy
before_save {self.title = title.upcase_first}
before_save {self.code = code.upcase}
validates :title, presence: true,
length: { minimum: 3, maximum: 50},
uniqueness: {case_sensitive: false}
validates :code, presence: true,
length: {minimum: 2},
uniqueness: {case_sensitive: false}
validates :building_id, presence: true
end
building.rb
class Building < ApplicationRecord
has_many :rooms, dependent: :destroy
before_save {self.title = title.upcase_first}
before_save {self.code = code.upcase}
validates :title, presence: true,
length: { minimum: 3, maximum: 50},
uniqueness: true
validates :code, presence: true,
length: {minimum: 3},
uniqueness: {case_sensitive: false}
end
Sorry for this long post and my lack of knowledge. I will appreciate any feedback.
You can specify the collection option using includes in the f.association. Like this:
f.association :room, :label_method => lambda { |room| "#{room.title} (#{room.building.title})", :collection => Room.includes(:building).all }

Rails has_many :through, cocoon

Player.rb
class Player < ApplicationRecord
belongs_to :user
has_many :player_games, dependent: :destroy, inverse_of: :player
has_many :games, :through => :player_games
validates :firstname, presence: true, length: { minimum: 3, maximum: 88 }
validates :lastname, presence: true, length: { minimum: 3, maximum: 88 }
validates :user_id, presence: true
accepts_nested_attributes_for :player_games, reject_if: :reject_posts, allow_destroy: true
def reject_posts(attributes)
attributes['game_id'].to_i == 0
attributes['score'].blank?
attributes['time'].blank?
end
def initialized_player_games # this is the key method
[].tap do |o|
Game.all.each do |game|
if g = player_games.find { |g| g.game_id == game.id }
o << g.tap { |g| g.enable ||= true }
else
o << PlayerGame.new(game: game)
end
end
end
end
end
players_controller.rb
class PlayersController < ApplicationController
before_action :set_player, only: [:edit, :update, :show, :destroy]
before_action :require_user, except: [:index, :show]
before_action :require_same_user, only: [:edit, :update, :destroy]
before_filter :process_player_games_attrs, only: [:create, :update]
def process_player_games_attrs
params[:player][:player_games_attributes].values.each do |game_attr|
game_attr[:_destroy] = true if game_attr[:enable] != '1'
end
end
.......
private
# Use callbacks to share common setup or constraints between actions.
def set_player
#player = Player.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def player_params
params.require(:player).permit(:id, :firstname, :lastname, player_games_attributes: [:id, :game_id, :score, :time, :enable, :_destroy] )
end
def require_same_user
if current_user != #player.user and !current_user.admin?
flash[:danger] = "You can edit or delete only your own player"
redirect_to root_path
end
end
end
_form of 'PLAYER'
<%= form_for(#player, :html => {class: "az-form", role: "form"}) do |player_form| %>
<%= player_form.label :firstname, class: "az-form__label" %> <br/>
<%= player_form.text_field :firstname, class: "az-form__input", placeholder: "Firstname of player", autofocus: true %>
<%= player_form.label :lastname, class: "az-form__label" %> </br>
<%= player_form.text_field :lastname, class: "az-form__input", placeholder: "Lastname of player" %>
<%= player_form.fields_for :player_games, #player.initialized_player_games do |builder| %>
<% #game = builder.object.game %>
<%= render 'result_fields', f: builder %>
<div class="links">
<%= link_to_add_association 'add result', player_form, :player_games, :partial => 'players/result_fields' %>
</div>
<hr>
<% end %>
<div class="text-center">
<%= button_tag(type: "submit", class: "az-form__submit") do %>
<%= player_form.object.new_record? ? "Create player" : "Update player" %>
<% end %>
</div>
<% end %>
_result_fields.html.erb
<div class="nested-fields">
<%= f.hidden_field :game_id, :value => #game.id%>
<div class="row">
<div class="col-md-12">
<label class="az-form__label az-form__label--unable js-az-form__checkbox" data-check="<%= #game.id %>">
<%= f.check_box :enable %>
<%= #game.title %>
</label>
</div>
</div>
<div class="row">
<div class="col-md-6">
<%= f.label :score,
class: "az-form__label", :data => {:check => #game.id } %> </br>
<%= f.number_field :score, step: :any, :data => {:check => #game.id },
class: "az-form__input az-form__input--disabled",
placeholder: "Score for '#{#game.title}'", disabled: true %>
</div>
<div class="col-md-6">
<%= f.label :time,
class: "az-form__label", :data => {:check => #game.id } %> </br>
<%= f.number_field :time, step: :any, :data => {:check => #game.id },
class: "az-form__input az-form__input--disabled",
placeholder: "Time for '#{#game.title}'", disabled: true %>
</div>
</div>
<div class="row">
<div class="col-md-12">
<%= link_to_remove_association "remove result", f %>
</div>
</div>
</div>
Question:
When edit 'player' have access to only one result per game, can not change others, conflict with 'initialized_player_games' method, but if i remove this method from form work well, but cannot create another game if dont create in new action, how can i change this method properly?
If I understand correctly, you want to add an entry for all games (which works), but adding a new Result does not. The problem is the #game which is probable either undefined or set to the last game.
I also do not really like the approach (giving the fields_for a specific set). Instead I would adapt the approach slightly. Instead of using initialized_player_games I would use a method, to be called in the controller, e.g. add_default_player_games, something like
def add_default_player_games
Game.all.each do |game|
if g = player_games.find { |g| g.game_id == game.id }
g.enable ||= true
else
player_games.build(game: game)
end
end
end
effectively adding new instances to the collection, without saving them.
So in your controller you would write
#player = Player.new
#player.add_default_player_games
or in edit
#player = Player.find(params[:id])
#player.add_default_player_games
Your view would then just iterate over player_games
<%= player_form.fields_for :player_games do |builder| %>
<%= render 'result_fields', f: builder %>
<% end %>
And then, if you would use simple-form it would be very easy to select a game if not yet selected, and there is no need for the ugly #game.
So do something like in _result_fields (in haml because I am a lazy typist)
.nested-fields
- game_id = f.object.game_id
- if game_id.present?
= f.hidden_field :game_id
- else
= f.collection_select :game_id, Game.all, :id, :name
...
So in short: if there is a game_id, do not allow to change it (would be useful to show the title of the game or something), but if not use a dropdown-select to choose the game.
And the rest stays the same (only use game_id instead of #game.id).

Showing errors in the modal rails

I'm very frustrated because I've been working on it for days and I haven't found a solution yet.
I have a Visit.rb model and, beyond the common validations, I have two more validations through two methods of mine (visit's start date cannot be prior to end one and there's no possibility to have two visits having the same start date, end date and visitor_id).
I need to show these errors set by me in the modal I'm giving to register a visit, but until now I've never had success.
In fact every time this error occurs: ArgumentError in VisitsController#create - First argument in form cannot contain nil or be empty
Here what I've done until now is...
Visit.rb
class Visit < ActiveRecord::Base
belongs_to :employee
belongs_to :visitor
default_scope -> { order(:created_at) }
validates :from, presence: true, uniqueness: { scope: [:to, :visitor_id] }
validates :to, presence: true
validates :visitor_id, presence: true
validates :employee_id, presence: true
validate :valid_date_range_required
validate :visit_uniqueness
def valid_date_range_required
if (from && to) && (to < from)
errors[:base] << "Visit's end date cannot be prior to the start one."
end
end
def visit_uniqueness
if Visit.find_by(from: :from, to: :to, visitor_id: :visitor_id)
errors[:base] << "A visit with the same start date, end date and visitor already exists."
end
end
end
visits_controller.rb
class VisitsController < ApplicationController
before_action :logged_in_employee, only: [:create, :destroy]
before_action :correct_employee, only: [:destroy, :update ]
def create
#visit = current_employee.visits.build(visit_params)
if #visit.save
flash[:success] = "Visit added"
redirect_to employee_path(session[:employee_id], :act => 'guestsVisits')
else
#visits = current_employee.visits.all
#employee = current_employee
render 'employees/guestsVisits'
end
end
private
def visit_params
params.require(:visit).permit(:from, :to, :visitor_id, :employee_id)
end
def correct_employee
#visit = current_employee.visits.find_by(id: params[:id])
redirect_to root_url if #visit.nil?
end
end
guestsVisits.rb (my view)
<div class="jumbotron3 text-center">
<div class="row">
<h1>Guests Visits</h1>
<hr>
<%=render :partial =>"layouts/sidebar"%>
<div class="panel3">
<div class="panel-body">
<!-- Modal for Visit -->
<% if logged_in? %>
<%=render :partial =>"shared/error_messages"%>
<a class="btn icon-btn btn-success pos" data-toggle="modal" data-target="#visitModal">
<span class="glyphicon btn-glyphicon glyphicon-plus img-circle text-success"></span>
Add a visit
</a>
<div id="visitModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Add Visit</h4>
</div>
<div class="modal-body">
<%= form_for(#visit) do |f| %>
<%= f.label :start_date %>
<%= f.date_field :from, class: 'form-control',:value => (f.object.from.strftime('%m/%d/%Y') if f.object.from) %>
<%= errors_for #visit, :from %><%if #visit.errors.any?%><br><%end%>
<br>
<%= f.label :end_date %>
<%= f.date_field :to, class: 'form-control',:value => (f.object.to.strftime('%m/%d/%Y') if f.object.to) %>
<%= errors_for #visit, :to %><%if #visit.errors.any?%><br><%end%>
<br>
<%= f.label :Visitor %>
<%= f.collection_select :visitor_id, Visitor.all, :id, :full_name, { :class=> "form-control", :include_blank => ''}%>
<%= errors_for #visit, :visitor_id %><%if #visit.errors.any?%><br><%end%>
<br>
<%= f.submit "Add visit", class: "btn btn-primary btn-color" %>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-info" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
I tried to use two different versions of error_messages.rb
error_messages.rb (1)
<% if #visit && #visit.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
×
The form contains <%= pluralize(#visit.errors.count, "error") %>.Open the modal for more details
</div>
</div>
<% end %>
error_messages.rb (2)
<% if #visit.errors.any? %>
<ul class="errors">
<% #visit.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
I hope someone can help me because I don't understand how to figure it out.
Thank you a lot.
EDIT:
class Employee < ActiveRecord::Base
before_save { self.email = email.downcase }
before_create :confirmation_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
has_many :macaddresss, dependent: :destroy
has_many :visits, dependent: :destroy
has_many :visitors, dependent: :destroy
#Validations
validates :name, presence: true , length: { maximum:20 , minimum: 2 }
validates :lastname, presence: true, length: { maximum:20 , minimum: 2 }
validates :gender, presence: true
validates :dateofbirth, presence: true
validates :birth_country, presence: true
validates :birth_place, presence: true, length: { maximum:60}
validates :contry_of_residence, presence: true
validates :city_of_residence, presence: true, length: { maximum:60 }
validates :address, presence: true, length: { maximum:60 , minimum: 7 }
validates :email, presence: true, length: { maximum:243 } ,format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }
validates :terms_of_service, acceptance: { message: 'accept terms and conditions' }
[...]
has_secure_password
def Employee.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
end
session_helper.rb
def current_employee
#current_employee ||= Employee.find_by(id: session[:employee_id])
end
EDIT2:
employees_controller.rb
class EmployeesController < ApplicationController
def show
if logged_in?
#employee = Employee.find(params[:id])
#indirizzimac = current_employee.indirizzimacs.new
#visitor = current_employee.visitors.new
#visit = current_employee.visits.new
#visits = current_employee.visits.all
if params[:act]=='myData'
render 'myData'
elsif params[:act]=='myNetwork'
render 'myData'
elsif params[:act]=='temporaryUsers'
render 'temporaryUsers'
elsif params[:act]=='guestsVisits'
render 'guestsVisits'
elsif params[:act]=='myAccount'
render 'myAccount'
else
render 'show'
end
else
render 'static_pages/errorPage'
end
end
end
From what i can see if creating visit fails you instantiate #visits and #employee instance variables then rendering 'employees/guestsVisits' its view you use #visit which i think it doesn't exist inside empleyees controller
So add it ad
def guestsVisits
#visit = current_employee.visits.build
end

Save successful on nested attributes on has many through but doesn't add to database

I and order and item system with Rails 4 with a has many through association. When I select create order the webpage says that the order was created successfully however the link is not made in the OrderItems linking tables meaning that the items relating to that order do not appear on the show page or edit page for an order.
The order is also linked to an employee. The current employee ID is linked to that order. I have just not been able to figure out how to add each item to the database.
p.s. I am using a gem called nested_form to handle all of the jQuery on the front end of dynamically adding and removing new items on the _form.html.erb for Orders.
orders_controller.rb
class OrdersController < ApplicationController
before_action :logged_in_employee, only:[:new, :show, :create, :edit, :update, :index]
before_action :admin_employee, only:[:destroy]
before_action :set_order, only: [:show, :edit, :update, :destroy]
def new
#order = Order.new
#items = Item.all
end
def edit
#items = Item.all
end
def create
#order = current_employee.orders.build(order_params)
if #order.save
flash[:success] = "Order successfully created"
redirect_to #order
else
render 'new'
end
end
def update
if #order.update_attributes(order_params)
flash[:success] = "Order updated!"
redirect_to current_employee
else
render 'edit'
end
end
....
private
def set_order
#order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:table_number, :number_of_customers, :status, :comment, order_items_attributes: [:id, :order_id, :item_id, :_destroy])
end
end
order.rb
class Order < ActiveRecord::Base
belongs_to :employee
has_many :order_items
has_many :items, :through => :order_items
default_scope { order('status DESC') }
validates :employee_id, presence: true
validates :table_number, numericality: { only_integer: true, greater_than: 0, less_than_or_equal_to: 20 }, presence: true
validates :number_of_customers, numericality: { only_integer: true, greater_than: 0, less_than_or_equal_to: 50 }, presence: true
validates :status, inclusion: { in: %w(Waiting Ready Closed), message: "%{value} is not a status" }
accepts_nested_attributes_for :order_items, :reject_if => lambda { |a| a[:item_id].blank? }
end
item.rb
class Item < ActiveRecord::Base
belongs_to :menu
has_many :order_items
has_many :orders, :through => :order_items
before_save { name.capitalize! }
VALID_PRICE_REGEX = /\A\d+(?:\.\d{0,2})?\z/
validates :name, presence: true, length: { maximum: 100 }
validates :price, format: { with: VALID_PRICE_REGEX }, numericality: { greater_than: 0, less_than_or_equal_to: 100}, presence: true
validates :course, inclusion: { in: %w(Starter Main Dessert Drink), message: "%{value} is not a course" }
validates :menu_id, presence: true
end
order_item.rb
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
validates :order_id, presence: true
validates :item_id, presence: true
end
orders/_form.html.erb
<% provide(:title, "#{header(#order)} #{#order.new_record? ? "order" : #order.id}") %>
<%= link_to "<< Back", :back, data: { confirm: back_message } %>
<h1><%= header(#order) %> <%= #order.new_record? ? "order" : #order.id %></h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= nested_form_for #order do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="row">
<div class="col-xs-6">
<%= f.label :table_number %>
<%= f.number_field :table_number, class: 'form-control' %>
</div>
<div class="col-xs-6">
<%= f.label :number_of_customers %>
<%= f.number_field :number_of_customers, class: 'form-control' %>
</div>
</div>
<%= f.fields_for :order_items do |oi| %>
<%= oi.grouped_collection_select :item_id, Menu.where(active: true).order(:name), :items, :name, :id, :name, { include_blank: 'Select Item' }, class: 'items_dropdown' %>
<%= oi.hidden_field :item_id %>
<%= oi.hidden_field :order_id %>
<%= oi.link_to_remove "Remove item" %>
<% end %>
<p><%= f.link_to_add "Add an item", :order_items %></p>
<br>
<% if !#order.new_record? %>
<%= f.label "Status" %>
<%= f.select(:status, options_for_select([['Waiting', 'Waiting'], ['Ready', 'Ready'], ['Closed', 'Closed']], #order.status), class: 'form-control') %>
<% end %>
<%= f.label "Comments - how would you like your steak cooked? Or feedback" %>
<%= f.text_area :comment, size: "20x5", class: 'form-control' %>
<%= f.submit submit_label(#order), class: "btn btn-success col-md-6" %>
<% end %>
<% if !#order.new_record? && current_employee.try(:admin?) %>
<%= link_to "Cancel", :back, data: { confirm: back_message }, class: "btn btn-warning col-md-offset-1 col-md-2" %>
<%= link_to "Delete", #order, method: :delete, data: { confirm: "Are you sure? The employee will be deleted! "}, class: "btn btn-danger col-md-offset-1 col-md-2" %>
<% else %>
<%= link_to "Cancel", :back, data: { confirm: back_message }, class: "btn btn-warning col-md-offset-1 col-md-5" %>
<% end %>
</div>
</div>
Issue: Let's say your order has got many items and you want the items to be saved just when the order is created.
order = Order.new(order_params)
item = Item.new(name: 'item-name', product_info: 'etc etc')
if order.save
item.create
order.items << item
end
You need to follow similar approach in your case. just get the item_params properly and apply above rule.
Try below approach, hope that helps. :)
def create
#order = current_employee.orders.build(order_params)
if #order.save
item = params["order"]["order_items_attributes"]
#please debug above one and try to get your items from params.
order_item = Item.create(item)
#makes sure above item hold all item attributes then create them first
#order.items << item
redirect_to #order
end
end

Resources