Books Controller:
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
# GET /books
# GET /books.json
def index
if params[:student_id]
student = Student.find(params[:student_id])
#books = student.books
else
#books = Book.all
end
respond_to do |format|
format.html
format.csv {render text: #books.to_csv }
end
end
def show
end
def new
#book = Book.new
end
def edit
end
def create
#book = Book.new(book_params)
respond_to do |format|
if #book.save
format.html { redirect_to #book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: #book }
else
format.html { render :new }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #book.update(book_params)
format.html { redirect_to #book, notice: 'Book was successfully updated.' }
format.json { render :show, status: :ok, location: #book }
else
format.html { render :edit }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
def destroy
#book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
#book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:book_name, :book_level, :total_words, :words_wrong, :self_corrections, :student_id)
end
end
Here is my "Students Controller"
class StudentsController < ApplicationController
def show
#student = Student.find(params[:id]) rescue nil
#books = Book.where(student_id: params[:id])
#book = Book.new
end
def create
student = Student.new(student_parameters)
student.user_id = current_user.id
if student.save
redirect_to student
else
redirect_to 'students#index'
end
end
def index
#students = Student.where("user_id = ?",current_user.id)
#student = Student.new
end
private
def student_parameters
params.require(:student).permit(:first_name, :last_name)
end
end
Books belong to students, and on the index view where I show an individual's students books, I want the heading at the top of the page to say "{current student}'s book". I'm unsure as to how to call the name of the current student, and I think the source of my confusion is the fact that I'm working with the books controller and student.first_name and student.last_name aren't available to me.
Additionally, I would like to know how to access book data when I'm using the students controller. For instance when I'm at localhost:3000/students/2, I'd like to show all that students books.
I'm looking for something like current_student.books or current_student.name, I think, but I'm not sure how to create them.
Instead of doing...
student = Student.find(params[:student_id])
#books = student.books
do...
#student = Student.find(params[:student_id])
#books = #student.books
This gives you the instance variable #student that you can use in your views, in particular #student.first_name and #student.last_name
you may want to condition the code in the view so that it only shows if #student is not nil (it would be nil if params[:student_id] wasn't passed).
Related
I have created this gem > https://rubygems.org/gems/badwordgem
This is my controller inside my rails project.
class AppointmentsController < ApplicationController
before_action :set_appointment, only: %i[ show edit update destroy ]
#before we run anything if the user is not signed in show index and show functions
before_action :authenticate_user!, except: [:index,:show]
#only the correct user can edit,update and destroy
before_action :correct_user, only: [:edit, :update , :destroy]
# GET /appointments or /appointments.json
def index
#appointments = Appointment.all.decorate
end
# GET /appointments/1 or /appointments/1.json
def show
end
# GET /appointments/new
def new
##appointment = Appointment.new
#appointment = current_user.appointments.build
end
# GET /appointments/1/edit
def edit
end
#function to allow for search functionality
def search
#appointments = Appointment.where("date LIKE?", "%"+params[:q]+"%")
end
# POST /appointments or /appointments.json
def create
##appointment = Appointment.new(appointment_params)
#appointment = current_user.appointments.build(appointment_params)
respond_to do |format|
if #appointment.save
format.html { redirect_to appointment_url(#appointment), notice: "Appointment was successfully created." }
format.json { render :show, status: :created, location: #appointment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /appointments/1 or /appointments/1.json
def update
respond_to do |format|
if #appointment.update(appointment_params)
format.html { redirect_to appointment_url(#appointment), notice: "Appointment was successfully updated." }
format.json { render :show, status: :ok, location: #appointment }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /appointments/1 or /appointments/1.json
def destroy
#appointment.destroy
respond_to do |format|
format.html { redirect_to appointments_url, notice: "Appointment was successfully destroyed." }
format.json { head :no_content }
end
end
#function here that restricts editing so the current logged in user can edit only their records
def correct_user
#appointment = current_user.appointments.find_by(id: params[:id])
redirect_to appointments_path, notice:"NOT ALLOWED TO EDIT THIS" if #appointment.nil?
end
private
# Use callbacks to share common setup or constraints between actions.
def set_appointment
#appointment = Appointment.find(params[:id])
end
# Only allow a list of trusted parameters through.
def appointment_params
params.require(:appointment).permit(:barber, :customer, :notes, :date,:user_id)
end
end
In my schema for the appointment model I have the column 'notes' which is where I want to filter bad words.
I want to integrate Badwordgem::Base.sanitize() into my controller so I can filter bad words when I am creating the appointment.
I've tried adding it here like so
def create
##appointment = Appointment.new(appointment_params)
#appointment.notes = Badwordgem::Base.sanitize(#appointment.notes)
#appointment = current_user.appointments.build(appointment_params)
but that throws undefined method `notes' for nil:NilClass
The gem has been tested with IRB and works. I am at a loss as to how to implement it inside my own rails project.
Where inside my controller do I add the method?
I would consider moving that logic into the model.
For example as a custom setter method:
# in app/models/appointment.rb
def notes=(notes)
sanitized_notes = Badwordgem::Base.sanitize(notes)
super(sanitized_notes)
end
Or as a before_validation:
# in app/models/appointment.rb
before_validation :sanitize_notes
private
def sanitize_notes
self.notes = Badwordgem::Base.sanitize(notes)
end
Both versions have the advantage that they make sure all notes are sanitized no matter how they are created and not just in this specific controller method. For example when you import Appointments via a rake task or the Rails console. Additionally, this makes testing a bit easier and you can use the default pattern in the controller like this:
#appointment = current_user.appointments.build(appointment_params)
respond_to do |format|
if #appointment.save
# ...
Funny how once you post you figure it out. . .
I added this inside my create function it to filter the bad words.
def create
##appointment = Appointment.new(appointment_params)
#appointment = current_user.appointments.build(appointment_params)
#appointment.notes = Badwordgem::Base.sanitize(#appointment.notes)
respond_to do |format|
if #appointment.save
format.html { redirect_to appointment_url(#appointment), notice: "Appointment was successfully created." }
format.json { render :show, status: :created, location: #appointment }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #appointment.errors, status: :unprocessable_entity }
end
end
end
I'm implementing a website using Ruby on Rails. I have a trouble which I cannot create a new data and save to my model. The error i got is this which the error pointed to the #vpermits = current_user.vpermits.build(vpermit_params). Anyone have idea on what I have i done wrong?
NoMethodError in VisitorPermitsController#create
undefined method `vpermits' for #<User:0x9b7b478>
def create
#vpermits = current_user.vpermits.build(vpermit_params)
if #vpermits.save
redirect_to #vpermits
else
This is my visitor_permits_controller.rb
class VisitorPermitsController < ApplicationController
before_action :set_vpermit, only: [:destroy]
def index
#vpermits = VisitorPermit.where(:user_id => current_user.id)
end
def new
#vpermits = VisitorPermit.new
end
def create
#vpermits = current_user.vpermits.build(vpermit_params)
if #vpermits.save
redirect_to #vpermits
else
render 'new'
end
end
def destroy
VisitorPermit.destroy_all(user_id: current_user)
respond_to do |format|
format.html { redirect_to root_path, notice: 'Permit was successfully canceled.' }
format.json { head :no_content }
end
end
def show
#vpermits = VisitorPermit.find(params[:id])
end
def update
#vpermits = VisitorPermit.where(user_id: current_user).take
respond_to do |format|
if #vpermits.update(vpermit_params)
format.html { redirect_to root_path}
flash[:success] = "Permit successfully updated"
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def edit
#vpermits = VisitorPermit.find(params[:id])
end
private
# Use callbacks to share common setup or constraints between actions.
def set_vpermit
#vpermits = VisitorPermit.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def vpermit_params
params.require(:visitor_permit).permit(:vehicle_type, :name, :department, :carplate, :duration, :permitstart, :permitend)
end
end
From your code you might have association(has_many) between User and VistorPermit models. And you gave your model name as VistorPermit. So the
line of code for buliding should be like this:
#vpermits = current_user.vistor_permits.build(vpermit_params)
I'm trying to create a form that allow called submits. I've got all the appropriate MVC created. I've then created a model called questions that works and am using active admin to allow admin users to add new questions to the form as they see fit. When I test submitting the form I get this error
undefined method `each' for nil:NilClass
#submit = Submit.new(submit_params)
#submit.save
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
Here's my submits controller:
class SubmitsController < ApplicationController
before_action :set_submit, only: [:show, :edit, :update, :destroy]
def index
#submits = Submit.all
end
def show
end
def new
#submit = Submit.new
#questions = Question.all
end
def edit
end
def create
#submit = Submit.new(submit_params)
#submit.save
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
respond_to do |format|
if #submit.save
format.html { redirect_to #submit, notice: 'Application was successfully created.' }
format.json { render :show, status: :created, location: #submit }
else
format.html { render :new }
format.json { render json: #submit.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #submit.update(submit_params)
format.html { redirect_to #submit, notice: 'Application was successfully updated.' }
format.json { render :show, status: :ok, location: #submit }
else
format.html { render :edit }
format.json { render json: #submit.errors, status: :unprocessable_entity }
end
end
end
def destroy
#submit.destroy
respond_to do |format|
format.html { redirect_to submits_url, notice: 'Submit was successfully destroyed.' }
format.json { head :no_content }
end
end
Here's my Submit and Question model:
Submit:
class Submit < ActiveRecord::Base
has_and_belongs_to_many :questions
belongs_to :user
end
Question:
class Question < ActiveRecord::Base
has_and_belongs_to_many :submits
end
I'm sure it's some kind of syntax error in my controller but I don't know what. Still pretty new to using join tables. Any help/explanation would be very appreciated.
Thanks!
You don't need this
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
I don't see your submit params but if you add question ids to the permitted parameters then rails will build the entry in the join table on it's own.
def submit_params
params.require(:submit).permit(:user_id, question_ids: [])
end
Struggling to get the create working for my nested routes in the following controller:
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
before_filter :load_author
# GET /books
# GET /books.json
def index
#books = #author.books.all
end
# GET /books/1
# GET /books/1.json
def show
end
# GET /books/new
def new
#book = #author.books.new
end
# GET /books/1/edit
def edit
end
# POST /books
# POST /books.json
def create
#book = #auhtor.books.new(book_params)
respond_to do |format|
if #book.save
format.html { redirect_to [#parent, #child], notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: #book }
else
format.html { render :new }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /books/1
# PATCH/PUT /books/1.json
def update
respond_to do |format|
if #book.update(book_params)
format.html { redirect_to #book, notice: 'Book was successfully updated.' }
format.json { render :show, status: :ok, location: #book }
else
format.html { render :edit }
format.json { render json: #book.errors, status: :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.json
def destroy
#book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
#book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:name, :author_id)
end
def load_author
#author = Author.find(params[:author_id])
end
end
I am getting the following error on line #29:
undefined method `books' for nil:NilClass
Any ideas? It correctly populates the author_id field in the create view but when i click save I get this error.
I'm sure you will laugh out loud after getting solution of the issue.
You have MIS-SPELLED instance object as #auhtor. It should be #author in first line of create action.
#book = #author.books.new(book_params)
In my Rails app, I have a comments scaffold which lets users comment on a movie.
I am faced with two problems.
The first problem is that anyone can create a comment, even if they are not signed in, how would I assign a comment to a user, so if there is a current_user, they can create a comment and I would be able to assign the user to the comment so <%= comment.user.first_name %>, and if they are not signed in, they cant create a comment. How would i do this? ( I am using devise )
The second problem is that when I create a comment, it takes me to this path (where 12 is :movie_id)
localhost:3000/movies/12/comments/new
This is fine but when i am creating the comment, I have to specify the movie_id (12), how this be done automatically, so rails sees that the movie_id for the comment is 12.
My Comments Controller, incase needed
class CommentsController < ApplicationController
# GET /comments
# GET /comments.json
before_filter :load_movie
def index
#comments = #movie.comments.all
#search = Movie.search(params[:q])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #comments }
end
end
# GET /comments/1
# GET /comments/1.json
def show
#comment = Comment.find(params[:id])
#search = Movie.search(params[:q])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #comment }
end
end
# GET /comments/new
# GET /comments/new.json
def new
#comment = Comment.new
#search = Movie.search(params[:q])
respond_to do |format|
format.html # new.html.erb
format.json { render json: #comment }
end
end
# GET /comments/1/edit
def edit
#comment = Comment.find(params[:id])
#search = Movie.search(params[:q])
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(params[:comment])
#search = Movie.search(params[:q])
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# PUT /comments/1
# PUT /comments/1.json
def update
#comment = Comment.find(params[:id])
#search = Movie.search(params[:q])
respond_to do |format|
if #comment.update_attributes(params[:comment])
format.html { redirect_to (#movie), notice: 'Comment 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
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url }
format.json { head :no_content }
end
end
private
def load_movie
#movie = Movie.find_by_id(:movie_id)
end
end
First:
using devise, you can request that a user is signed in by saying at the top of your controller:
before_filter :authenticate_user!, only: [:new,:create]
so if someone not signed in tries to access these actions, they are redirected to the sign in page and after sign in forwarded to the original request.
Second:
As you can see from the routes, 12 is assigned to params[:movie_id]. So in your controllers new action write:
#movie = Movie.find(params[:movie_id])
#comment = #movie.comments.new
#comment.user=current_user