While creating a search form I am facing a problem. I am getting the following error:
undefined method `model_name' for NilClass:Class
This is my view file:
"datepicker" %>
This is my clients_controller.rb:
class ClientsController < ApplicationController
def newClients
end
end
And this is my model client.rb:
class Client < ActiveRecord::Base
# attr_accessible :title, :body
end
I am confused in using form_for parameter. Can any one explain it briefly how and why to use form_for parameter?
Edit 1
I have modified my controller as
class ClientsController < ApplicationController
def search
redirect_to root_path
end
end
Once i click submit button it showing error as
No route matches [GET] "/search"
You are missing something here. Let me explain.
In your controller you don't need to define a custom method (called newClients) since Rails conventions suggest to use the following:
class ClientsController < ApplicationController
# GET /clients
def index
#clients = Client.all
end
# GET /clients/:id
def show
#client = Client.find(params[:id])
end
# GET /clients/new
def new
#client = Client.new
end
# POST /clients
def create
#client = Client.new(params[:client])
if #client.save
redirect_to :back, success: "Successfully created..."
else
render :new
end
end
# GET /clients/:id/edit
def edit
#client = Client.find(params[:id])
end
# PUT /clients/:id
def update
#client = Client.find(params[:id])
if #client.update_attributes(params[:client])
redirect_to :back, success: "Successfully edited..."
else
render :edit
end
end
# DELETE /clients/:id
def destroy
#client = Client.find(params[:id]).destroy
redirect_to :back, success: "Successfully deleted..."
end
end
And finally, in order for your form_for to work properly, you need to pass it an instance of a class:
form_for #client
where #client is Client.new in your case.
First of all in your controller please follow Rails naming conventions. The method name should be new_clients or new.
def new
#client = Client.new
end
Your view name should be new.html.erb.
You are not defining #client in your controller, but in the view you are using it.
Related
**I made a controller and model for post and not able to show my post's
title on the show page but repeatedly i am getting the same error **
my posts_controller code :
class PostsController < ApplicationController
def index
end
def new
end
def create
#render plain: params[:post][:body].inspect
#post = Post.new(post_params)
if #post.save
redirect_to posts_path
else
render "new"
end
end
def show
#post= Post.find(:id=>params[:id])
# #article = "prateek"
end
private
def post_params
params.require(:post).permit(:title,:body)
end
end
my show.html.erb file :
<h1><%= #post.title %></h1>
my post.rb file:
class Post < ApplicationRecord
end
**I expect the result but I didn't get anything right
error = NoMethodError in Posts#show
undefined method `title' for nil:NilClass**
You're passing an hash to find, while you're suppose to pass just the id.
#post= Post.find(params[:id])
or use find_by if you want to pass an hash
#post= Post.find_by(:id => params[:id])
New to rails. Following a tutorial on polymorphic associations, I bump into this to set #client in create and destroy.
#client = Client.find(params[:client_id] || params[:id])
I'm normally only used to that you can only find #client = Client.find(params[:id])
so how does this work with there being two params? How does the || work?
FavoriteClientsController.rb:
class FavoriteClientsController < ApplicationController
def create
#client = Client.find(params[:client_id] || params[:id])
if Favorite.create(favorited: #client, user: current_user)
redirect_to #client, notice: 'Leverandøren er tilføjet til favoritter'
else
redirect_to #client, alert: 'Noget gik galt...*sad panda*'
end
end
def destroy
#client = Client.find(params[:client_id] || params[:id])
Favorite.where(favorited_id: #client.id, user_id: current_user.id).first.destroy
redirect_to #client, notice: 'Leverandøren er nu fjernet fra favoritter'
end
end
Full code for controller, models can be seen here
Using rails 5
Expression: params[:client_id] || params[:id] is the same as:
if params[:client_id]
params[:client_id]
else
params[:id]
end
Wow thats an incredibly bad way to do it.
A very extendable and clean pattern for doing controllers for polymorphic children is to use inheritance:
class FavoritesController < ApplicationController
def create
#favorite = #parent.favorites.new(user: current_user)
if #favorite.save
redirect_to #parent, notice: 'Leverandøren er tilføjet til favoritter'
else
redirect_to #parent, alert: 'Noget gik galt...*sad panda*'
end
end
def destroy
#favorite = #parent.favorites.find_by(user: current_user)
redirect_to #parent, notice: 'Leverandøren er nu fjernet fra favoritter'
end
private
def set_parent
parent_class.includes(:favorites).find(param_key)
end
def parent_class
# this will look up Parent if the controller is Parents::FavoritesController
self.class.name.deconstantize.singularize.constantify
end
def param_key
"#{ parent_class.naming.param_key }_id"
end
end
We then define child classes:
# app/controllers/clients/favorites_controller.rb
module Clients
class FavoritesController < ::FavoritesController; end
end
# just an example
# app/controllers/posts/favorites_controller.rb
module Posts
class FavoritesController < ::FavoritesController; end
end
You can then create the routes by using:
Rails.application.routes.draw do
# this is just a routing helper that proxies resources
def favoritable_resources(*names, **kwargs)
[*names].flatten.each do |name|
resources(name, kwargs) do
scope(module: name) do
resource :favorite, only: [:create, :destroy]
end
yield if block_given?
end
end
end
favoritable_resources :clients, :posts
end
The end result is a customizable pattern based on OOP instead of "clever" code.
The tutorial which teaches you to do
Client.find(params[:client_id] || params[:id])
is a super-duper bad tutorial :) I strongly recommend you to switch to another one.
Back to the topic: it is logical OR: if first expression is neither nil or false, return it, otherwise return second expression.
That thing is just trying to find client by client_id if there is one in the request params. If not it's trying to find client by id.
However such practic can make you much more pain than profit.
In my application I have a "bookings" table, and an "extras" table.
This is a many-many relationship. Therefore I have created a middle table called "additions"
I've used the "has_many :through" to establish the relationship between the tables:
class Booking < ActiveRecord::Base
has_many :additions
has_many :extras, :through => :additions
class Extra < ActiveRecord::Base
has_many :additions
has_many :extras, :through => :additions
class Addition < ActiveRecord::Base
belongs_to :booking
belongs_to :extra
This seems to work. I added a few extras to some existing bookings manually (by adding numbers to the additions table), and wrote code so that when you click to show a booking, it lists all associated extras.
Now I need to make it so that when you make a booking - the "extras" are saved into the middle (additions) table.
I have checkboxes on my bookings form page:
<%= f.label 'Extras:' %>
<%= f.collection_check_boxes :extra_ids, Extra.all, :id, :extra_info %>
But obviously, the choices just get discarded when the user clicks on save.
I need some code to go (in the controller?) to make it save these "extras" into the "additions table" ?
Any ideas, as I can't work out how to do this?!
Thanks!
class BookingsController < ApplicationController
respond_to :html, :xml, :json
before_action :find_room
# before_action :find_extra
def index
#bookings = Booking.where("room_id = ? AND end_time >= ?", #room.id, Time.now).order(:start_time)
respond_with #bookings
end
def new
#booking = Booking.new(room_id: #room.id)
end
def create
#booking = Booking.new(params[:booking].permit(:room_id, :start_time, :length, :user_id))
#booking.room = #room
if #booking.save
redirect_to room_bookings_path(#room, method: :get)
else
render 'new'
end
end
def show
#booking = Booking.find(params[:id])
end
def destroy
#booking = Booking.find(params[:id]).destroy
if #booking.destroy
flash[:notice] = "Booking: #{#booking.start_time.strftime('%e %b %Y %H:%M%p')} to #{#booking.end_time.strftime('%e %b %Y %H:%M%p')} deleted"
redirect_to room_bookings_path(#room)
else
render 'index'
end
end
def edit
#booking = Booking.find(params[:id])
end
def update
#booking = Booking.find(params[:id])
# #booking.room = #room
if #booking.update(params[:booking].permit(:room_id, :start_time, :length, :user_id))
flash[:notice] = 'Your booking was updated succesfully'
if request.xhr?
render json: {status: :success}.to_json
else
redirect_to resource_bookings_path(#room)
end
else
render 'edit'
end
end
private
def save booking
if #booking.save
flash[:notice] = 'booking added'
redirect_to room_booking_path(#room, #booking)
else
render 'new'
end
end
def find_room
if params[:room_id]
#room = Room.find_by_id(params[:room_id])
end
end
# def find_extra
# if params[:extra_id]
# #extra = Extra.find_by_id(params[:extra_id])
# end
# end
# If resource not found redirect to root and flash error.
def resource_not_found
yield
rescue ActiveRecord::RecordNotFound
redirect_to root_url, :notice => "Booking not found."
end
def booking_params
params.require(:booking).permit(:user_id, :extra_id)
end
end
------------------------
class AdditionsController < ApplicationController
before_action :set_addition, only: [:show, :edit, :update, :destroy]
# GET /additions
def index
#additions = Addition.all
end
# GET /additions/1
def show
end
# GET /additions/new
def new
#addition = Addition.new
end
# GET /additions/1/edit
def edit
end
# POST /additions
def create
#addition = Addition.new(addition_params)
if #addition.save
redirect_to #addition, notice: 'Addition was successfully created.'
else
render :new
end
end
# PATCH/PUT /additions/1
def update
if #addition.update(addition_params)
redirect_to #addition, notice: 'Addition was successfully updated.'
else
render :edit
end
end
# DELETE /additions/1
def destroy
#addition.destroy
redirect_to additions_url, notice: 'Addition was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_addition
#addition = Addition.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def addition_params
params.require(:addition).permit(:booking_id, :extra_id, :extra_name)
end
end
--------------------------------------
# #author Stacey Rees <https://github.com/staceysmells>
class ExtrasController < ApplicationController
# #see def resource_not_found
around_filter :resource_not_found
before_action :set_extra, only: [:show, :edit, :update, :destroy]
def index
#extras = Extra.all
end
def show
end
def new
#extra = Extra.new
end
def edit
end
def create
#extra = Extra.new(extra_params)
if #extra.save
redirect_to #extra, notice: 'Extra was successfully created.'
else
render :new
end
end
def update
if #extra.update(extra_params)
redirect_to #extra, notice: 'Extra was successfully updated.'
else
render :edit
end
end
def destroy
#extra.destroy
redirect_to extras_url, notice: 'Extra was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_extra
#extra = Extra.find(params[:id])
end
# If resource not found redirect to root and flash error.
def resource_not_found
yield
rescue ActiveRecord::RecordNotFound
redirect_to root_url, :notice => "Room Category not found."
end
# Only allow a trusted parameter "white list" through.
def extra_params
params.require(:extra).permit(:extraimg, :name, :description, :quantity, :price, :extracat_id)
end
end
What you're doing here is working with nested form attributes. It's a bit complex, but it's also something people do often, so there are some good resources available.
I suggest you look at this post: http://www.sitepoint.com/complex-rails-forms-with-nested-attributes/
In particular, the section named 'More Complicated Relationships' specifically has an example of using nested attributes to set up a many-to-many association using has_many :through.
The key pieces (which commenters have already pointed out) are going to be accepts_nested_attributes_for :extras in your Booking model, and a f.fields_for :extras block in the view. You'll also need to modify your booking_params method to permit the nested values. There are a couple of strong parameters gotchas that you can potentially run into with that, so you may need to review the documentation.
It turns out I was nearly there with the code I had once the accepts_nested_attributes_for was written in.
My main issue was setting up the booking_params method in the controller. I got it to work by declaring :extra_ids => [] in my params.permit.
I am trying to build nested routes and as mentioned here I m trying to edit my boat picture as <%= link_to "edit", edit_boat_picture_path(#boat, picture) %>. But when I try it, it throws an error undefined local variable or methodpicture' for #<#:0x007f9637811ee0>`
my picture controller is; (probably destroy is wrong also)
class PicturesController < ApplicationController
before_action :logged_in_user
before_filter :load_parent
def index
#picture = #boat.pictures.all
end
def new
#picture = #boat.pictures.new
end
def show
#pictures = #boat.pictures.find(params[:id])
end
def create
#picture = #boat.pictures.new(picture_params)
if #picture.save
#flash[:success] = "Continue from here"
render 'show'
else
render 'new'
end
end
def edit
#picture = Picture.find(params[:id])
end
def update
#picture = #boat.pictures.find(params[:id])
if #picture.update_attributes(picture_params)
flash[:notice] = "Successfully updated picture."
render 'show'
else
render 'edit'
end
end
def destroy
#picture = #boat.pictures.find(params[:id])
#picture.destroy
flash[:notice] = "Successfully destroyed picture."
redirect_to #picture.boat
end
private
def picture_params
params.require(:picture).permit(:name, :image)
end
def load_parent
#boat = Boat.find(params[:boat_id])
end
end
Presumably you should change
<%= link_to "edit", edit_boat_picture_path(#boat, picture) %>
to
<%= link_to "edit", edit_boat_picture_path(#boat, #picture) %>
The key there being changing picture to #picture. The reason to do this is that you're declaring #picture (an instance variable) in your controller, not picture (a local variable). When declaring and defining an instance variable in a method in your controller, it's also accessible in the corresponding view. However, when declaring a local variable in a method in your controller, it is not available in your view.
So even if you had declared picture rather than #picture in your controller method, it wouldn't be accessible in your view, since it's a local variable.
For more information on the five types of ruby variables, see this link.
Have a issue with a controller file which i have narrowed down to a method
Controller
def create
#gallery = Gallery.new(params[:gallery])
if #gallery.save
flash[:notice] = "Successfully created gallery."
redirect_to #gallery
else
render :action => 'new'
end
end
private
def gallery_params
params.require(:gallery).permit(:name, :gallery, :gamepic)
end
end
the problem is that there is no attr_accessible in the controller or the model
model
class Gallery < ActiveRecord::Base
has_many :gamepics
private
def gallery_params
params.require(:gallery).permit(:name, :gallery, :gamepic)
end
end
Try passing the strong parameters method into Gallery.new instead of params[:gallery].
My understanding of this is that, the hash returned from that method is what should be used anyways. So you'd have:
#gallery = Gallery.new(gallery_params)
If you only need certain params from your :permit call, just make a new strong params method and use that one.