I am new in Ruby and I have to finish my school project. I have problem because we make one project in 14 people, everyone has his own part. I have to create new appointment but someone used this before and I cannot use this again (I want to add this simple from form). Please help me because I am stuck now, I don't want change someone's code. I render _form51.html.erb from new51.html.erb. Maybe I can use any simple redirect to create51?;> But I don't know how ;(
EDITED:
NOW SOLVED BUT why app create always empty appointment?
Routes.rb:
ZOZ::Application.routes.draw do
resources :refferals do
collection do
get 'new51'
end
member do
get 'show'
end
end
resources :appointments do
collection do
get 'search' #17
get 'search_result' #17
get 'to_confirm' #17
get 'search_not' #57
get 'search_result_not' #57
get 'add_or_edit_not' #57
get 'searchdate'
get 'searchd'
get 'move'
get 'new51'
post :create51
end
member do
put :confirm #17
put :update_not #57
get 'show51'
end
end
resources :clinics do
collection do
get 'index51'
end
member do
get 'show51s'
end
end
resources :doctors do
collection do
get 'index51a'
get 'index51'
get 'search54'
get 'search_result54'
get 'show_harmonogram'
end
member do
get 'show51s'
get 'show51ss'
end
end
resources :patients do
collection do
get 'select51'
get 'index51'
end
member do
get 'show51s'
get 'show51ss'
end
end
get "welcome/index2"
get "welcome/index"
get 'appointments/create'
get 'appointments/move' => 'appointments#move'
post 'appointments/move' => 'appointments#doctors_list'
get 'appointments/move/:id' => 'appointments#doctor_appointments', as: :doctor_appointments
get 'appointments/change_appointment/:id' => 'appointments#change_appointment', as: :change_appointment
get 'appointments/change_doctor_and_appointment/:id' => 'appointments#change_doctor_and_appointment', as: :change_doctor_and_appointment
get 'appointments/success' => 'appointments#success'
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
root :to => 'welcome#index'
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id))(.:format)'
end
_form51.html.erb:
<%= form_for(#appointment) do |f| %>
<% if #appointment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#appointment.errors.count, "error") %> prohibited this appointment from being saved:</h2>
<ul>
<% #appointment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :data_godzina_wizyty %><br />
<%=
options = { start_year: 2.year.from_now.year,
end_year: 2013,
include_blank: true,
default: nil }
f.datetime_select :data_godzina_wizyty, options
%>
<!--<input type="text" data-behaviour='datepicker' :data_wizyty > -->
</div>
<div class="field">
<%= f.hidden_field :doctor_id, :value => Doctor.find(session[:current_doctor_id2]).id %>
</div>
<div class="field">
<%= f.hidden_field :patient_id, :value => Patient.find(session[:current_patient_id]).id %>
</div>
<div class="actions">
<%= submit_tag "Utworz wizyte" %>
</div>
<% end %>
New51.html.erb:
<div id="container">
<center>
<h1>Nowa wizyta:</h1>
<p>Sprawdz poprawnosc ponizszych danych a nastepnie uzupelnij formularz.</p>
<h3>Dane lekarza:</h3>
<p>
<strong>Imię lekarza:</strong>
<%= Doctor.find(session[:current_doctor_id2]).imie_lekarza %>
</p>
<p>
<strong>Nazwisko lekarza:</strong>
<%= Doctor.find(session[:current_doctor_id2]).nazwisko_lekarza %>
</p>
<p>
<strong>Specjalizacja lekarza:</strong>
<%= Doctor.find(session[:current_doctor_id2]).specjalizacja %>
</p>
<h3>Dane pacjenta:</h3>
<p>
<strong>Imie:</strong>
<%= Patient.find(session[:current_patient_id]).imie %>
</p>
<p>
<strong>Nazwisko:</strong>
<%= Patient.find(session[:current_patient_id]).nazwisko %>
</p>
<p>
<strong>Pesel:</strong>
<%= Patient.find(session[:current_patient_id]).pesel %>
</p>
<%= render 'form51' %>
<%= link_to 'Wybierz innego lekarza', index51_doctors_path %>
</br>
</center>
</div>
Appointments_Controller:
class AppointmentsController < ApplicationController
before_filter :load_appointment, only: [:show, :update, :edit, :destroy]
before_filter :load_wizard, only: [:new, :edit, :create]
def searchd
end
def move
end
def doctors_list
#doctors = Doctor.where("imie_lekarza like ? or nazwisko_lekarza LIKE ? or specjalizacja LIKE ?", "%#{params[:search]}%", "%#{params[:search]}%", "%#{params[:search]}%")
end
def doctor_appointments
#doctor = Doctor.find(params[:id])
#appointments = #doctor.appointments
end
def change_appointment
#appointment = Appointment.find(params[:id])
end
def change_doctor_and_appointment
#doctors = Doctor.all
#appointment = Appointment.find(params[:id])
end
def success
#notice = flash[:notice]
end
def searchdate
d = params[:date]
data = Date.new(d["(1i)"].to_i, d["(2i)"].to_i, d["(3i)"].to_i)
#appointments = Appointment.scoped
#appointments = #appointments.where(:data_godzina_wizyty => data.beginning_of_day..data.end_of_day)
end
def search_not
end
def search_result_not
#pacjent
#patients = Patient.scoped
#patients = #patients.where(pesel: params[:pesel])
d = params[:date]
if d["(1i)"] != "" and d["(2i)"]. != "" and d["(3i)"] != ""
data = Date.new(d["(1i)"].to_i, d["(2i)"].to_i, d["(3i)"].to_i)
#appointments = #patients.first.appointments.where(:data_godzina_wizyty => data.beginning_of_day..data.end_of_day)
else
#appointments = #patients.first.appointments
end
end
def add_or_edit_not
session['last_search_not'] = request.env["HTTP_REFERER"]
#appointment = Appointment.find(params[:id])
#patient = Patient.find(#appointment.patient_id)
if #appointment.doctor_id != nil
#doctor = Doctor.find(#appointment.doctor_id)
end
if #appointment.refferal_id != nil
#refferal = Refferal.find(#appointment.refferal_id)
end
end
def update_not
#appointment = Appointment.find(params[:id])
#appointment.notatka = params[:notatka]
if #appointment.save
redirect_to session[:last_search_not], notice: 'Notatka zostala zapisana.'
else
redirect_to :back, notice: 'Niestety wystapil blad. Prosze sprubowac pozniej'
end
end
def search
end
def new51
#appointment = Appointment.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #appointment }
end
end
def create51
#appointment = Appointment.new(params[:patient])
respond_to do |format|
if #appointment.save
format.html { redirect_to #appointment, notice: 'Szczegoy wizyty pomyslnie zmodyfikowane!' }
format.json { render json: #appointment, status: :created, location: #appointment }
else
format.html { render action: "new" }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
def search_result
d = params[:date]
data = Date.new(d["(1i)"].to_i, d["(2i)"].to_i, d["(3i)"].to_i)
#szukanie pacjenta
#patients = Patient.scoped
#patients = #patients.where(pesel: params[:pesel])
if params[:imie] != ""
#patients = #patients.where(imie: params[:imie])
end
if params[:nazwisko] != ""
#patients = #patients.where(nazwisko: params[:nazwisko])
end
#szukanie doctora
opcja = 0
#doctors = Doctor.scoped
if params[:imie_lekarza] != ""
#doctors = #doctors.where(imie_lekarza: params[:imie_lekarza])
opcja = 1
end
if params[:nazwisko_lekarza] != ""
#doctors = #doctors.where(nazwisko_lekarza: params[:nazwisko_lekarza])
opcja = 1
end
#zlaczenie
#patient_appo = #patients.first.appointments.where(:data_godzina_wizyty => data.beginning_of_day..data.end_of_day, potwierdzona: false)
if opcja == 1
#doctors_appo = #doctors.first.appointments.where(:data_godzina_wizyty => data.beginning_of_day..data.end_of_day, potwierdzona: false)
#appointments = #patient_appo & #doctors_appo
else
#appointments = #patient_appo
end
end
def to_confirm
session['last_search'] = request.env["HTTP_REFERER"]
#appointment = Appointment.find(params[:id])
#patient = Patient.find(#appointment.patient_id)
if #appointment.doctor_id != nil
#doctor = Doctor.find(#appointment.doctor_id)
end
if #appointment.refferal_id != nil
#refferal = Refferal.find(#appointment.refferal_id)
end
end
def confirm
#appointment = Appointment.find(params[:id])
#appointment.potwierdzona = true
if #appointment.save
#redirect_to :back, notice: 'Rejestracja zostala pomyslnie potwierdzona.'
redirect_to session[:last_search], notice: 'Rejestracja zostala pomyslnie potwierdzona.'
else
redirect_to :back, notice: 'Niestety wystapil blad. Prosze sprubowac pozniej'
end
end
def index
#appointments = Appointment.all
end
def show
end
def new
#appointment = #wizard.object
#clinics = Clinic.all
#doctors = Doctor.all
end
public
def findDoctorViaClinic( clinic )
return( (Clinic.find( clinic )).doctors.uniq )
end
helper_method :findDoctorViaClinic
def findScheduleViaDoctor(d)
s = Schedule.includes(:doctors_workplace).where(doctors_workplace_id: (DoctorsWorkplace.includes(:doctor).where(doctor_id: d)) ).where(taken: 0)
return s
end
helper_method :findScheduleViaDoctor
def edit
end
def create
#appointment = #wizard.object
if #wizard.save
s = ( Schedule.find( #appointment.schedule.id ) )
s.taken = true
s.save
redirect_to #appointment, notice: "Appointment saved!"
else
render :new
end
end
def update
# if #wizard.save
# redirect_to #appointment, notice: 'Appointment was successfully updated.'
# else
# render action: 'edit'
# end
#appointment = Appointment.find(params[:id])
#old_appointment = #appointment.dup
respond_to do |format|
if #appointment.update_attributes(params[:appointment])
DefaultMailer.move_appointment(#appointment, #old_appointment).deliver
format.html { redirect_to appointments_success_path, notice: 'Pomyslnie zmieniono termin.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
def destroy
#appointment.destroy
redirect_to appointments_url
end
private
def load_appointment
#appointment = Appointment.find(params[:id])
end
def load_wizard
#wizard = ModelWizard.new(#appointment || Appointment, session, params)
if self.action_name.in? %w[new edit]
#wizard.start
elsif self.action_name.in? %w[create update]
#wizard.process
end
end
end
Logs:
Started POST "/appointments/create51" for 127.0.0.1 at 2014-06-22 08:22:53 +0200
Processing by AppointmentsController#create51 as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"kMxnErrH13opSkUPbg9hRM0Sy5JVwDCAbGRDNP5BSfc=", "appointment"=>{"data_godzina_wizyty(1i)"=>"2015", "data_godzina_wizyty(2i)"=>"1", "data_godzina_wizyty(3i)"=>"17", "data_godzina_wizyty(4i)"=>"16", "data_godzina_wizyty(5i)"=>"15", "doctor_id"=>"1", "patient_id"=>"1"}, "commit"=>"Utworz wizyte"}
[1m[35m (0.0ms)[0m begin transaction
[1m[36mSQL (2.0ms)[0m [1mINSERT INTO "appointments" ("clinic_id", "created_at", "data_godzina_wizyty", "data_wizyty", "doctor_id", "godzina_wizyty", "notatka", "objawy_choroby", "patient_id", "potwierdzona", "refferal_id", "schedule_id", "updated_at", "wymaga_Potwierdzenia") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)[0m [["clinic_id", nil], ["created_at", Sun, 22 Jun 2014 06:22:53 UTC +00:00], ["data_godzina_wizyty", nil], ["data_wizyty", nil], ["doctor_id", nil], ["godzina_wizyty", nil], ["notatka", nil], ["objawy_choroby", nil], ["patient_id", nil], ["potwierdzona", nil], ["refferal_id", nil], ["schedule_id", nil], ["updated_at", Sun, 22 Jun 2014 06:22:53 UTC +00:00], ["wymaga_Potwierdzenia", nil]]
[1m[35m (13.0ms)[0m commit transaction
Redirected to http://localhost:3000/appointments/30
Completed 302 Found in 23.0ms (ActiveRecord: 15.0ms)
Started GET "/appointments/new51" for 127.0.0.1 at 2014-06-22 08:22:42 +0200
Processing by AppointmentsController#new51 as HTML
[1m[35mDoctor Load (1.0ms)[0m SELECT "doctors".* FROM "doctors" WHERE "doctors"."id" = ? LIMIT 1 [["id", 1]]
[1m[36mCACHE (0.0ms)[0m [1mSELECT "doctors".* FROM "doctors" WHERE "doctors"."id" = ? LIMIT 1[0m [["id", 1]]
[1m[35mCACHE (0.0ms)[0m SELECT "doctors".* FROM "doctors" WHERE "doctors"."id" = ? LIMIT 1 [["id", 1]]
[1m[36mPatient Load (0.0ms)[0m [1mSELECT "patients".* FROM "patients" WHERE "patients"."id" = ? LIMIT 1[0m [["id", 1]]
[1m[35mCACHE (0.0ms)[0m SELECT "patients".* FROM "patients" WHERE "patients"."id" = ? LIMIT 1 [["id", 1]]
[1m[36mCACHE (0.0ms)[0m [1mSELECT "patients".* FROM "patients" WHERE "patients"."id" = ? LIMIT 1[0m [["id", 1]]
[1m[35mCACHE (0.0ms)[0m SELECT "doctors".* FROM "doctors" WHERE "doctors"."id" = ? LIMIT 1 [["id", 1]]
[1m[36mCACHE (0.0ms)[0m [1mSELECT "patients".* FROM "patients" WHERE "patients"."id" = ? LIMIT 1[0m [["id", 1]]
Rendered appointments/_form51.html.erb (13.0ms)
Rendered appointments/new51.html.erb within layouts/application (22.0ms)
Rendered welcome/_form.html.erb (1.0ms)
Completed 200 OK in 103.0ms (Views: 100.9ms | ActiveRecord: 1.0ms)
Started GET "/appointments/30" for 127.0.0.1 at 2014-06-22 08:22:53 +0200
Processing by AppointmentsController#show as HTML
Parameters: {"id"=>"30"}
[1m[36mAppointment Load (0.0ms)[0m [1mSELECT "appointments".* FROM "appointments" WHERE "appointments"."id" = ? LIMIT 1[0m [["id", "30"]]
Rendered appointments/show.html.erb within layouts/application (2.0ms)
Rendered welcome/_form.html.erb (1.0ms)
Completed 200 OK in 80.0ms (Views: 77.0ms | ActiveRecord: 0.0ms)
Routes
Wow your routes are really WET
You really need to read up on resourceful routing - every route you have in your routes file really needs to be associated to a particular controller (apart from root to and other wildcards)
Whoever wrote your routes file has laden it with massive numbers of specific actions. Frankly, it's a mess and I would highly recommend you go through & remove any custom actions you've got in there.
Resourceful routing is described in the Rails docs as thus:
Bottom line is you shouldn't be creating routes for specific records; you need to create a system to handle the different processes your application will have
--
Form
If you're not seeing any object created in your db, there could be a number of problems. The biggest, though, is your use of an #instance variable in your partial.
To the best of my knowledge, partials don't carry #instance variables through to their render process. You have to pass local variables:
#new.html.erb
<%= render "form51", locals: { appointment: #appointment } %>
#_form51.html.erb
<%= form_for appointment do |f| %>
...
<% end %>
--
Being honest, there's so much to fix with this, it will be best if you ask for help in the comments here - so I can pinpoint exactly what needs to be fixed
You problem comes from the url you use on your form.
You should try like this on your _form51.html.erb:
form_for #appointment, :url => url_for(:action => "create51") do |f|
If you do rake routes | grep 'create51' you'll have the rails path. Then you can also do like this:
form_for #appointment, :url => create51_path do |f|
(here I suppose the command gave you create51 as path).
Related
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.
How can we get it where only the correct_user can create or destroy here?
class DaysMissedController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: [:create, :destroy]
def create
habit = Habit.find(params[:habit_id])
habit.missed_days = habit.missed_days + 1
habit.save!
level = habit.levels.find(params[:level_id])
level.missed_days = level.missed_days + 1
if level.missed_days == 3
level.missed_days = 0
level.days_lost += habit.calculate_days_lost + 1
end
level.save!
head :ok
end
def destroy
habit = Habit.find(params[:habit_id])
habit.missed_days = habit.missed_days - 1
habit.save
level = habit.levels.find(params[:level_id])
level.missed_days = level.missed_days - 1
level.save!
head :ok
end
private
def correct_user
#habit = current_user.habits.missed_days.find_by(id: params[:id]) #I've tried different versions of this line
redirect_to habits_path, notice: "Not authorized to edit this habit" if #habit.nil?
end
end
Depending on what I put in the line where I commented I either get "Not authorized to edit this habit" or upon refreshing the page the checkmark I had made disappears even if I am the correct_user
habit.js
$(document).ready(function()
{
$(".habit-check").change(function()
{
habit = $(this).parent().siblings(".habit-id").first().attr("id");
level = $(this).siblings(".level-id").first().attr("id");
if($(this).is(":checked"))
{
$.ajax(
{
url: "/habits/" + habit + "/levels/" + level + "/days_missed",
method: "POST"
});
}
else
{
$.ajax(
{
url: "/habits/" + habit + "/levels/" + level + "/days_missed/1",
method: "DELETE"
});
}
});
});
In habit show page this is what I don't want other users to be able to edit via :create & :destroy:
<% if #habit.current_level_strike %>
<div class="btn" id="red"> <label id="<%= #habit.id %>" class="habit-id">Strikes:</label>
<% else %>
<div class="btn" id="gold"> <label id="<%= #habit.id %>" class="habit-id-two">Strikes:</label>
<% end %>
<% #habit.levels.each_with_index do |level, index| %>
<% if #habit.current_level >= (index + 1) %>
<p>
<% if #habit.current_level_strike %>
<label id="<%= level.id %>" class="level-id">Level <%= index + 1 %>:</label>
<% else %>
<label id="<%= level.id %>" class="level-id-two">Level <%= index + 1 %>:</label>
<% end %>
<%= check_box_tag nil, true, level.missed_days > 0, {class: "habit-check"} %>
<%= check_box_tag nil, true, level.missed_days > 1, {class: "habit-check"} %>
<%= check_box_tag nil, true, level.missed_days > 2, {class: "habit-check"} %>
</p>
<% end %>
<% end %>
rails console
[2] pry(main)> Habit.find(1)
Habit Load (17.7ms) SELECT "habits".* FROM "habits" WHERE "habits"."id" = ? LIMIT 1 [["id", 1]]
=> #<Habit:0x007f96c7133728
id: 1,
conceal: false,
missed_days: 0,
likes: 1,
committed: ["mon", "tue", "wed", "thu", "fri", ""],
date_started: Sun, 07 Jun 2015 00:00:00 UTC +00:00,
trigger: "",
action: "test",
target: "",
reward: "",
private_submit: nil,
user_id: 1,
created_at: Sun, 07 Jun 2015 21:57:04 UTC +00:00,
updated_at: Wed, 10 Jun 2015 00:45:05 UTC +00:00,
order: nil>
[3] pry(main)> Level.find(1)
Level Load (14.0ms) SELECT "levels".* FROM "levels" WHERE "levels"."id" = ? LIMIT 1 [["id", 1]]
=> #<Level:0x007f96c7838c80
id: 1,
habit_id: 1,
missed_days: 0,
current_level: nil,
created_at: Sun, 07 Jun 2015 21:57:04 UTC +00:00,
updated_at: Wed, 10 Jun 2015 00:45:05 UTC +00:00,
days_lost: 0>
[4] pry(main)>
habits_controller
class HabitsController < ApplicationController
before_action :set_habit, only: [:show, :edit, :update, :destroy, :like]
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
def index
if params[:tag]
#habits = Habit.tagged_with(params[:tag])
else
#habits = current_user.habits.order("date_started DESC")
end
end
def show
#habit = Habit.find(params[:id])
#notable = #habit
#notes = #notable.notes
#note = Note.new
#commentable = #habit
#comments = #commentable.comments
#comment = Comment.new
#correct_user = current_user.habits.find_by(id: params[:id])
end
def new
#habit = current_user.habits.build
end
def edit
end
def create
#habit = current_user.habits.build(habit_params)
if (params[:commit] == 'conceal')
#habit.conceal = true
#habit.save_with_current_level
redirect_to #habit, notice: 'Habit was successfully created'
elsif
#habit.save_with_current_level
track_activity #habit
redirect_to #habit, notice: 'Habit was successfully created'
else
flash.now[:danger] = 'Required Fields: "Committed to", "Started", and "Enter Habit"'
render 'new'
end
end
def update
if #habit.update(habit_params)
redirect_to #habit, notice: 'Habit was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#habit.destroy
redirect_to habits_url
end
def like
#habit = Habit.find(params[:id])
#habit_like = current_user.habit_likes.build(habit: #habit)
if #habit_like.save
#habit.increment!(:likes)
flash[:success] = 'Thanks for liking!'
else
flash[:error] = 'Two many likes'
end
redirect_to(:back)
end
private
def set_habit
#habit = Habit.find(params[:id])
end
def correct_user
#habit = current_user.habits.find_by(id: params[:id])
redirect_to habits_path, notice: "Not authorized to edit this habit" if #habit.nil?
end
def habit_params
params.require(:habit).permit(
:user_id,
:trigger,
:tag_list,
:current_level,
:missed_days,
:target,
:reward,
:comment,
:commentable,
:like,
:likeable,
:private,
:action,
:order,
:date_started,
:missed_one,
:notes_text,
:notes_date,
:notable,
:note,
:committed => [],
levels_attributes: [
:missed_days,
:days_lost], notes_attributes: [:notable, :note, :notes_text, :notes_date, :_destroy])
end
end
Here's the gist of it (not fully updated but you get the idea)
Please let me know if you need further explanation or code to help you help me :)
UPDATE ERROR
Started POST "/habits/1/levels/2/days_missed" for 127.0.0.1 at 2015-06-10 13:07:11 -0400
Processing by DaysMissedController#create as */*
Parameters: {"habit_id"=>"1", "level_id"=>"2"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
Habit Load (0.2ms) SELECT "habits".* FROM "habits" WHERE "habits"."user_id" = ? [["user_id", 1]]
ActsAsTaggableOn::Tag Load (0.2ms) SELECT "tags".* FROM "tags" WHERE (LOWER(name) = LOWER('ingrain'))
CACHE (0.0ms) SELECT "habits".* FROM "habits" WHERE "habits"."user_id" = ? [["user_id", 1]]
Level Load (0.2ms) SELECT "levels".* FROM "levels" WHERE "levels"."habit_id" = ? [["habit_id", 1]]
(0.2ms) SELECT COUNT(*) FROM "habits" WHERE "habits"."user_id" = ? [["user_id", 1]]
Completed 404 Not Found in 21ms
ActiveRecord::RecordNotFound (Couldn't find Habit without an ID):
app/controllers/days_missed_controller.rb:32:in `correct_user'
So I believe you've correctly identified that the problem lies within your correct_user method:
def correct_user
#habit = current_user.habits.missed_days.find_by(id: params[:id])
redirect_to habits_path, notice: "Not authorized to edit this habit" if #habit.nil?
end
Take a look at your first line, here's what I read in English:
Take the current User
Get that User's Habits
Get those Habits' MissedDays
Find me one of those missed days that matches params[:id]
Which, based on your data model, is sort of non-sensical. Missed Days is an attribute of a model, not a model itself. I'm not sure you can even call .find_by on a number, which makes it unsurprising that you keep getting nil.
I bet this'll work instead:
#habit = current_user.habits.find(params[:habit_id])
Note that the find method always queries by the id attribute. Saved you a few characters. :)
One other thing, in both create and destroy, you re-find the habit that you already found in the before_action. Try this:
def create
#habit.missed_days = habit.missed_days + 1
#habit.save
...
end
I am using following form and controller. If I create a new notification everything gets saved except the campus_id.
It seems to give the wrong campus parameter although I select a different one from the dropdown. If I edit the same entry afterwards then it does get saved? What is going on and how do I fix it?
The same form is used for the edit and create actions. (it is a partial)
It might be worth noting that I use shallow routes for the campus (has_many) and notifications(belongs_to).
routes.rb
shallow do
resources :campus do
resources :notifications
end
end
Form:
<%= form_for [#campus,#notification] do |f| %>
<% if #notification.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#notification.errors.count, "error") %> prohibited this notification from being saved:</h2>
<ul>
<% #notification.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :post %><br>
<%= f.text_area :post %>
</div>
<div class="field">
<%= f.label :campus %><br>
<%= f.collection_select(:campus_id, Campus.all.order('name ASC'), :id, :name, prompt: true) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This is the controller:
class NotificationsController < ApplicationController
before_action :set_notification, only: [:show, :edit, :update, :destroy]
before_action :set_campus, only: [:index, :new, :create]
def index
#notifications = #campus.notification
end
def show
end
def new
#notification = #campus.notification.new
end
def edit
end
def create
#notification = #campus.notification.new(notification_params)
respond_to do |format|
if #notification.save
format.html { redirect_to #notification, notice: 'Notification was successfully created.' }
format.json { render action: 'show', status: :created, location: #notification }
else
format.html { render action: 'new' }
format.json { render json: #notification.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #notification.update(notification_params)
format.html { redirect_to #notification, notice: 'Notification was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #notification.errors, status: :unprocessable_entity }
end
end
end
def destroy
#notification.destroy
respond_to do |format|
format.html { redirect_to campu_notifications_url(1) }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_notification
#notification = Notification.find(params[:id])
end
def set_campus
#campus = Campus.find(params[:campu_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def notification_params
params.require(:notification).permit(:post, :campus_id)
end
end
If I look at the log I see the wrong parameter is comitted.
Started POST "/campus/1/notifications" for 84.193.153.106 at
2014-09-29 18:29:33 +0000 Started POST "/campus/1/notifications" for
84.193.153.106 at 2014-09-29 18:29:33 +0000 Processing by NotificationsController#create as HTML Processing by
NotificationsController#create as HTML Parameters: {"utf8"=>"_",
"authenticity_token"=>"oNSlEFeukwEj2hIAT89wFdIYwjHO5c8lzBlCqMyk31Y=",
"notification"=>{"post"=>"sdqfdsfd", "campus_id"=>"3"},
"commit"=>"Create Notification", "campu_id"=>"1"} Parameters:
{"utf8"=>"_",
"authenticity_token"=>"oNSlEFeukwEj2hIAT89wFdIYwjHO5c8lzBlCqMyk31Y=",
"notification"=>{"post"=>"sdqfdsfd", "campus_id"=>"3"},
"commit"=>"Create Notification", "campu_id"=>"1"} Campus Load
(0.4ms) SELECT "campus".* FROM "campus" WHERE "campus"."id" = $1
LIMIT 1 [["id", "1"]] Campus Load (0.4ms) SELECT "campus".* FROM
"campus" WHERE "campus"."id" = $1 LIMIT 1 [["id", "1"]] (0.1ms)
BEGIN (0.1ms) BEGIN SQL (28.6ms) INSERT INTO "notifications"
("campus_id", "created_at", "post", "updated_at") VALUES ($1, $2, $3,
$4) RETURNING "id" [["campus_id", 1], ["created_at", Mon, 29 Sep 2014
18:29:34 UTC +00:00], ["post", "sdqfdsfd"], ["updated_at", Mon, 29 Sep
2014 18:29:34 UTC +00:00]] SQL (28.6ms) INSERT INTO "notifications"
("campus_id", "created_at", "post", "updated_at") VALUES ($1, $2, $3,
$4) RETURNING "id" [["campus_id", 1], ["created_at", Mon, 29 Sep 2014
18:29:34 UTC +00:00], ["post", "sdqfdsfd"], ["updated_at", Mon, 29 Sep
2014 18:29:34 UTC +00:00]] (3.5ms) COMMIT (3.5ms) COMMIT
Might want to change your new and create actions like this:
def new
#notification = #campus.notifications.build
end
def create
#notification = #campus.notifications.build(notification_params)
respond_to do |format|
if #notification.save
format.html { redirect_to #notification, notice: 'Notification was successfully created.' }
format.json { render action: 'show', status: :created, location: #notification }
else
format.html { render action: 'new' }
format.json { render json: #notification.errors, status: :unprocessable_entity }
end
end
end
campus.build_notification will instantiate a notification that belongs_to campus. Using new would require you to pass notification[campus_id] as part of your params.
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.
I use polymorphic associations with comments. When I try to add 'edit' and also 'destroy' in show template, I get the error in the title (just edit for now). How do I add both links to show?
comments_controller.rb
class CommentsController < ApplicationController
....
before_action :signed_in_user, only: [:new, :edit]
before_filter :load_commentable
def index
#commentable = load_commentable
#comments = #commentable.comments
end
def show
end
def edit
#commentable = load_commentable
end
def new
#commentable = load_commentable
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
#comment.user = current_user
if #comment.save
redirect_to #comment, notice: "Created."
else
render :new
end
end
def update
#comment = #commentable.comments.build(comment_params)
#comment.user = current_user
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to #comment, notice: 'It was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
private
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
....
end
show.html.erb template
<%= link_to "Edit", [:edit, #commentable, :comment] %>
form
<%= form_for [#commentable, #comment] do |f| %>
....
full trace
log
Processing by CommentsController#show as HTML
Parameters: {"post_id"=>"1", "id"=>"2"}
Comment Load (0.3ms) SELECT "comments".* FROM "comments" WHERE
"comments"."id" = ? LIMIT 1 [["id", "2"]]
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" =
? LIMIT 1 [["id", "1"]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" =
? ORDER BY "users"."id" ASC LIMIT 1 [["id", 2]]
(0.2ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."user_id" =
? [["user_id", 2]] CACHE (0.0ms) SELECT COUNT(*) FROM "comments"
WHERE "comments"."user_id" = ? [["user_id", 2]]
Rendered comments/show.html.erb within layouts/application (10.7ms)
Completed 500 Internal Server Error in 19ms
ActionView::Template::Error (No route matches {:action=>"edit",
:controller=>"comments", :post_id=>#, :id=>nil,
:format=>nil} missing required keys: [:id]):
25: <div class="thumbsdown"><%= link_to image_tag('othericons/thumbiconDown.PNG', height: '20', width: '20'),
"#" %>
26: <%= link_to image_tag('othericons/flagicon.PNG', height: '20', width: '18'), "#"
%>
27:
28: <%= link_to "Edit", [:edit, #commentable, :comment] %> 29:
30:
31: app/views/comments/show.html.erb:28:in
`_app_views_comments_show_html_erb___2937579164590753686_69833853514120'
Rendered /home/action/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb
(1.6ms) Rendered
/home/action/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(1.2ms) Rendered
/home/action/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/template_error.erb
within rescues/layout (19.1ms)
routes:
resources :posts do
resources :comments
end
Change the Edit Link as below:
<%= link_to "Edit", edit_post_comment_path(#commentable, #comment) %>
You have setup Post and Comment as nested routes, so you need to pass objects of Post as well as Comment to the edit path.
EDIT
For Polymorphic association, you could use it as below:
<%= link_to "Edit", [:edit, #commentable, #comment] %>