Am trying to save the form data into my database
but for some reason I keep getting an error.
Am fairly new to ruby so am not too sure what the problem is.
Am trying to create a new book entry and here is what I have so far.
books.controller
class BooksController < ApplicationController
def new
#book = Book.new
end
def create
#book = Book.new(book_params)
if #book.save
redirect_to new_book_path
end
end
private
def book_params
params.require(:book).permit(:title, :description, :author, :status, :isbn_number)
end
end
There error am getting is:
NameError in BooksController#create
undefined local variable or method `new_book_path' for #<BooksController:0xe3f5ae8>
I have a form that I fill in all those details but when I try to submit, I get that error. Its saying the error is on the redirect but I don't know whats wrong.
routes
Rails.application.routes.draw do
resources :books, :only => [:new, :create]
get 'page/books'
get 'page/about'
get 'page/contact'
get 'page/home'
devise_for :users
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'page#home'
end
looks like your routes file has an issue:
your config/routes.rb file should have the following
resources :books, :only => [:new, :create]
For a more complete answer:
The error you are getting is saying the line
redirect_to new_book_path
is throwing an error because it does not understand the variable new_book_path.
This variable gets created/handled via your routes file.
Just try changing this line
redirect_to new_book_path
to
render 'new'
Related
I have a Subscriber model that takes in a "phone_number" and a "visit" integer. I have two controllers Subscribers and Visits(super and sub) I have never worked with nested controllers before and I'm having some issues with namespace I believe. Because I getting back the uninitialized constant error. Basically the subscriber controller signs up a subscriber and the visit controller counts the amount of times they've visited by user input of their phone_number. Why am I getting this error? I'll show my code for clarity.
CONTROLLERS
class Subscribers::VisitsController < ApplicationController
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.find_by_phone_number(params[:phone_number])
if #subscriber
#subscriber.visit += 1
#subscriber.save
redirect_to subscribers_visits_new_path(:subscriber)
else
render "new"
end
end
end
class SubscribersController < ApplicationController
def index
#subscriber = Subscriber.all
end
def new
#subscriber = Subscriber.new
end
def create
#subscriber = Subscriber.create(subscriber_params)
if #subscriber.save
flash[:success] = "Subscriber Has Been successfully Created"
redirect_to new_subscriber_path(:subscriber)
else
render "new"
end
end
ROUTES
Rails.application.routes.draw do
devise_for :users
resources :subscribers, except: :show
get '/subscribers/visits/new', to: 'subscribers/visits#new'
root "welcomes#index"
VIEWS
<h1>hey</hey>
<%= form_for #subscriber do |form| %>
<div class="form-group">
<p>
<%= form.label :phone_number %>
<%= form.text_field :phone_number %>
</p>
<% end %>
ERROR
Hmm, my guess is you are trying to route url subscriber/visits/new to new action in VisitsController?How about changing this line:
get '/subscribers/visits/new', to: 'subscribers/visits#new'
to:
namespace :subscribers do
get '/visits/new', to: 'visits#new'
end
Also try to move this block above resources :subscribers, except: :show if you still get the error.
Cheers
You probably do not need to inherit one controller from another. Simply define the controllers as you normally would:
app/controllers/subscribers_controller.rb
class SubscribersController < ApplicationController
# methods for Subscribers
end
in app/controllers/visits_controller.rb
class VisitsController < ApplicationController
# methods for Visits
end
Note that these must to be located in separate files, so that Rails can find the correct source file by the name of the object that it's looking for. This is a Rails naming convention.
Regarding your routes, you'll need to change to use one of 4 route formats. Reading the section on Adding More RESTful Actions in the Rails Routing from the Outside In guide might help.
1) To route visits as a nested resource, which is what it appears you're actually trying to do, you would use this:
resources :subscribers, except: :show do
resources :visits
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/:id/visits/new
POST /subscribers/:id/visits
GET /subscribers/:id/visits
GET /subscribers/:id/visits/:id
GET /subscribers/:id/visits/:id/edit
PATCH /subscribers/:id/visits/:id/update
DELETE /subscribers/:id/visits/:id/destroy
This is the typical route structure for nested resources and separate controllers.
2) To make visits#new a simple collection (non-member) action in the VisitsController, then you likely want this:
resources :subscribers, except: :show do
collection do
get 'visits/new', to 'visits#new'
post 'visits', to 'visits#create'
end
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/visits/new
POST /subscribers/visits
This is typically used to add new top-level routes in an existing resource and controller.
3) To construct visits as member actions, use this:
resources :subscribers, except: :show do
member do
get 'visits/new', to 'visits#new'
post 'visits', to 'visits#create'
end
end
This will produce these routes:
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
GET /subscribers/:id/visits/new
POST /subscribers/:id/visits
This is normally used to add new member routes in an existing resource and controller.
4) To simply make visits routes appear to be included in subscribers, you could use this:
get '/subscribers/visits/new', to: 'visits#new'
post '/subscribers/visits', to: 'visits#create'
resources :subscribers, except: :show
This will produce these routes:
GET /subscribers/visits/new
POST /subscribers/visits
GET /subscribers/new
POST /subscribers
GET /subscribers
GET /subscribers/:id/edit
PATCH /subscribers/:id/update
DELETE /subscribers/:id/destroy
This may be used to make arbitrary routes appear to be included in an existing resource, when they really may be independent.
So I always thought routes was straightforward but it clearly isn't. I want my page to show data.html.erb but it keeps on showing show.html.erb. These are my only two views in the user folder
My controller is:
class UserController < ApplicationController
def data
render :json => User.including_relationships
end
end
and my routes.rb is:
Rails.application.routes.draw do
get 'users/:data' => 'users#data'
resources :user
end
I always seem to get the show.html.erb page instead of the data.html.erb. Im sure there's something easy to fix here but what?
The : before data in your route denotes a variable, try
Rails.application.routes.draw do
get 'users/data' => 'users#data'
resources :user
end
I am trying to setup a custom route. However whenever I hit the beverage_locations/new page, it tries to send 'new' in the url as the :location_id in the index path.
route.rb
controller 'beverage_locations' do
get 'beverage_locations/:location_id' => 'beverage_locations#index'
get 'beverage_locations/new' => 'beverage_locations#new'
end
error
ActiveRecord::RecordNotFound in BeverageLocationsController#index
Couldn't find Location with id=new
any idea how to fix this?
Thanks!
Rails routes are matched in the order they are specified, so if you
have a resources :photos above a get 'photos/poll' the show action’s
route for the resources line will be matched before the get line. To
fix this, move the get line above the resources line so that it is
matched first.
From http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
A demo:
# beverage_locations_controller.rb
class BeverageLocationsController < ApplicationController
def index
render :text => params[:location_id]
end
def new
render :text => 'New method'
end
end
# config/routes.rb
Forfun::Application.routes.draw do
controller 'beverage_locations' do
get 'beverage_locations/new' => 'beverage_locations#new'
get 'beverage_locations/:location_id' => 'beverage_locations#index'
end
end
# http://localhost:3000/beverage_locations/1234 => 1234
# http://localhost:3000/beverage_locations/new => New method
You need to swap the order of the routes so that the new action has preference:
controller 'beverage_locations' do
get 'beverage_locations/new' => 'beverage_locations#new'
get 'beverage_locations/:location_id' => 'beverage_locations#index'
end
class CommentsController < ApplicationController
def create
#commentable= context_object()
#comment = #commentable.comments.build(params[:comment].merge(:user_id => current_user.id))
if #comment.save
respond_to do |format|
format.js
end
else
render :action => 'new'
end
end
private
def context_object
params[:constraint][:context_type].singularize.classify.constantize.find( context_id )
end
def context_id
params["#{ params[:constraint][:context_type].singularize }_id"]
end
end
This commenting module has served me well but I ran into a hitch this morning, possibly because of my use of nested resources. Essentially, I now have a URL like:
/projects/3/albums/6/attachments/84
When I comment on that page, I get the error:
ActiveRecord::RecordNotFound (Couldn't find Project without an ID):
app/controllers/comments_controller.rb:102:in `context_object'
app/controllers/comments_controller.rb:14:in `create'
My routes file looks like:
resources :projects do
resources : albums do
resources :attachments
end
end
resources :attachments do
resources :comments, :only => [:create, :update,:destroy],
:constraint => {:context_type => "conversations"}
end
Any ideas on how I can get the commenting module to play nicely with commenting on project>Album>Attachment ?
Thanks for the input,
Posting this as an answer in order not to clutter the comments to the original question.
Since you don't have the requirement to keep attachments available via /attachments - making the second resources block useless, do something like this:
resources :projects do
resources :albums do
resources :attachments do
resources :comments, :only => [:create, :update,:destroy],
:constraint => {:context_type => "conversations"}
end
end
end
That's going to change your routes helpers (_path and _url), go through your controller(s) and view(s) and change them to reflect your new helpers.
Specifically, attachment_comments_path becomes project_album_attachment_comments_path.
The full list of routes for those models can be viewed by running rake routes in a console. I'd also recommend you take a closer look to the Rails routing guide.
I have a controller with the 7 RESTful actions plus an additional 'current' action, which returns the first active foo record:
class FooController < ApplicationController
def current
#user = User.find(params[:user_id])
#foo = #user.foos.where(:active => true).first
#use the Show View
respond_to do |format|
format.html { render :template => '/foos/show' }
end
end
#RESTful actions
...
end
The Foo Model :belongs_to the User Model and the User Model :has_many Foos.
If I structure the routes as such:
resources :users do
resources :foos do
member do
get :current
end
end
end
The resulting route is '/users/:user_id/foos/:id'. I don't want to specify the foo :id, obviously.
I've also tried:
map.current_user_foo '/users/:user_id/current_foo', :controller => 'foos', :action => 'current'
resources :users do
resources :foos
end
The resulting route is more like I would expect: '/users/:user_id/current_foo'.
When I try to use this route, I get an error that reads:
ActiveRecord::RecordNotFound in FoosController#current
Couldn't find Foo without an ID
edit
When I move the current action to the application controller, everything works as expected. The named route must be conflicting with the resource routing.
/edit
What am I missing? Is there a better approach for the routing?
I think you want to define current on the collection, not the member (the member is what is adding the :id).
try this.
resources :users do
resources :foos do
collection do
get :current
end
end
end
Which should give you a route like this:
current_user_foos GET /users/:user_id/foos/current(.:format) {:controller=>"foos", :action=>"current"}
Also map isn't used anymore in the RC, it will give you a deprecation warning.