I am trying to create a REST API for my app.
The map.connect_resource :book causes the following error, when executing rake test:functionals:
Error: undefined local variable or method `map' for #
<ActionDispatch::Routing::Mapper:0x8a11e74>.
In my app, I'm trying to implement RoR with MySQL with the following table data.
Table Name: Object
Fields: object_id, Object_name, Object_description etc...
I would like to create a REST API object for querying the above database and retrieving the data. What's the best way to proceed?
That is a reallyyyyyyy old tutorial (from 6 years ago!!!). I would recommend reading this guide instead: http://guides.rubyonrails.org/routing.html
Assuming you are running Rails 3, you should just put this in your routes.rb file:
resources :books
That will expose routes for your BooksController so you can access:
HTTP Verb Path action used for
-----------------------------------------------------------------------
GET /books index display a list of all books
GET /books/new new return an HTML form for creating a new book
POST /books create create a new book
GET /books/:id show display a specific book
GET /books/:id/edit edit return an HTML form for editing a book
PUT /books/:id update update a specific book
DELETE /books/:id destroy delete a specific book
So in your BooksController you would then have:
class BooksController < ApplicationController
# GET /books
# GET /books.xml
def index
#books = Book.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #books }
end
end
# GET /books/1
# GET /books/1.xml
def show
#book = Book.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #book }
end
end
# GET /books/new
# GET /books/new.xml
def new
#book = Book.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #book }
end
end
# GET /books/1/edit
def edit
#book = Book.find(params[:id])
end
# POST /books
# POST /books.xml
def create
#book = Book.new(params[:book])
respond_to do |format|
if #book.save
format.html { redirect_to(#book, :notice => 'Book was successfully created.') }
format.xml { render :xml => #book, :status => :created, :location => #book }
else
format.html { render :action => "new" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
# PUT /books/1
# PUT /books/1.xml
def update
#book = Book.find(params[:id])
respond_to do |format|
if #book.update_attributes(params[:book])
format.html { redirect_to(#book, :notice => 'Book was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #book.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.xml
def destroy
#book = Book.find(params[:id])
#book.destroy
respond_to do |format|
format.html { redirect_to(books_url) }
format.xml { head :ok }
end
end
end
Related
Tearing my hair out here. I have a brand model, this has_many projects and the projects belong_to the brand. I'm trying to create projects inside the brand but I'm running into the following error:
undefined method `projects_path'
Everything seems to be in order. Some of my code can be found below:
Routes
resources :brands do
resources :projects do
resources :ideas
end
end
Brands
<%= link_to 'Create New Project', new_brand_project_path(#brand) %>
The routing is working, as the link I'm sent to is brand/brand_id/projects/new - but this is where I get the error I mentioned earlier.
Update - The original problem was fixed, now when I save the project I'm getting the same error, but this time something is wrong with 'create'...
class ProjectsController < ApplicationController
# GET /projects
# GET /projects.json
def index
#projects = Project.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #projects }
end
end
# GET /projects/1
# GET /projects/1.json
def show
#project = Project.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #project }
end
end
# GET /projects/new
# GET /projects/new.json
def new
#brand = Brand.find(params[:brand_id])
#project = Project.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #project }
end
end
# GET /projects/1/edit
def edit
#project = Project.find(params[:id])
end
# POST /projects
# POST /projects.json
def create
#project = Project.new(params[:project])
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render json: #project, status: :created, location: #project }
else
format.html { render action: "new" }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
Add #brand = Brand.find(params[:brand_id]) to all your methods.
Remember the view comes back to the controller each time and can't remember what was set last time. The new method builds you the html form, but the create method is used to take the data and create the new record. But the create method doesn't know what you did in new, it can only work from the parameter data it was given.
How does rails know how to map to each function in the controller if the routes.rb file only specifies:
resources :users
but inside the UsersController you have
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, :notice => 'User was successfully created.' }
format.json { render :json => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, :notice => 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
How does rails determine that for instance the index function maps to GET/users while the create function maps to POST/users?
How does resources :users even know to map to the UsersController?
Rails is based around the 'convention over configuration' paradigm.
As such, the "resources :users" line indicates that all the standard CRUD methods are supported by the corresponding UsersController <-- the 'Users' prefix matches to the Controller, Model etc.
Please check the rails routes guide: http://guides.rubyonrails.org/routing.html
And to see in practice what the routes declaration does issue this command in your project directory:
rake routes
Also as mentioned before, stick with conventions and remember that rails is a very opinionated piece of software.
A basic overview of my app. There is currently two models. A jobs model and a clients model. Both models have a has_and_belongs_to_many relationship as I intended to allow the user to create a client entry and then assign them one or many jobs.
Here are both of my models.
Clients -
class Client < ActiveRecord::Base
has_and_belongs_to_many :job
end
Jobs -
class Job < ActiveRecord::Base
has_and_belongs_to_many :client
end
I have been doing some research and I think im right in thinking that the relationship needs a foreign key to function so have added a client_id column & a job_id column to my database.
The clients page is currently working and here is my controller for that.
class ClientsController < ApplicationController
def index
#clients = Client.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #clients }
end
end
# GET /Clients/1
# GET /Clients/1.json
def show
#clients = Client.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #clients }
end
end
# GET /Clients/new
# GET /Clients/new.json
def new
#clients = Client.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #clients }
end
end
# GET /Clients/1/edit
def edit
#clients = Client.find(params[:id])
end
def create
#clients = Client.new(params[:client])
respond_to do |format|
if #clients.save
format.html { redirect_to #clients, notice: 'Client was successfully created.' }
format.json { render json: #clients, status: :created, location: #clients }
else
format.html { render action: "new" }
format.json { render json: #clients.errors, status: :unprocessable_entity }
end
end
end
# PUT /Clients/1
# PUT /Clients/1.json
def update
#clients = Client.find(params[:id])
respond_to do |format|
if #clients.update_attributes(params[:client])
format.html { redirect_to #clients, notice: 'Client was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #clients.errors, status: :unprocessable_entity }
end
end
end
# DELETE /Clients/1
# DELETE /Clients/1.json
def destroy
#clients = Client.find(params[:id])
#clients.destroy
respond_to do |format|
format.html { redirect_to :clients , notice: 'Client was successfully removed.'}
format.json { head :no_content }
end
end
def details
#clients = Client.find_by_id(params[:id])
#jobs = Client.job
end
end
And here's what I currently have for my jobs controller.
class JobsController < ApplicationController
def index
#jobs = Job.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #job }
end
end
def new
#jobs = Job.new
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #job }
end
end
def create
#jobs = Job.new(params[:job])
#cients = Client.find = Client.find(params[:id])
respond_to do |format|
if #jobs.save
format.html { redirect_to(#jobs,
:notice => 'Job was successfully created.') }
format.xml { render :xml => #jobs,
:status => :created, :location => #Job }
else
format.html { render :action => "new" }
format.xml { render :xml => #jobs.errors,
:status => :unprocessable_entity }
end
end
end
end
In my jobs form I was given thr following code which added a drop down with all the created clients.
<%= select("job", "client_id", Client.all.collect {|c| [ c.name, c.id ] }, {:include_blank => 'None'})%>
When I press save though. I recieve the following error.
unknown attribute: client_id
Application Trace | Framework Trace | Full Trace
app/controllers/jobs_controller.rb:22:in `new'
app/controllers/jobs_controller.rb:22:in `create'
I assume this is because I need to define a way of finding the client_id in my job creation as well as specifying one in my client creation.
This is my first rails app though so im not quite sure how.
Any help would be greatly appreciated.
Your jobs table doesn't have a client_id, nor should it. You need to create a junction table to facilitate a many-to-many relationship. It should be called clients_jobs and contain an integer client_id and job_id.
There is a lot more wrong here. Here are just the things I caught at a casual glance:
This line:
#cients = Client.find = Client.find(params[:id])
should be:
#cients = Client.find(params[:id])
Pluralization is important in Rails. A client doesn't have many "job". It has many jobs. Your models should reflect this:
class Client < ActiveRecord::Base
has_and_belongs_to_many :jobs
end
class Job < ActiveRecord::Base
has_and_belongs_to_many :clients
end
You'll need to create a junction table via a migration, which is where your foreign keys will exist:
$ rails g migration AddClientsJobsTable
In index and new, you first create #jobs = Job.new and then you render it via :xml => #job. Again, pluralization is important. You need #job = Job.new. You have the same problem in create, except you've dropped the 's' and capitalized the 'J': :location => #Job } You can't do that in programming. Case and spelling both matter.
Job.find(:all) or Client.all: Pick one. Don't mix find :all and .all.
#clients = Client.find(params[:id]). You're finding a single specific Client, not a collection of clients. Your variable should be called #client. This is not an error, but it is seriously ugly.
pluralize your jobs and clients in your associations. I.E
has_many_and_belongs_to :jobs
has_many_and_belongs_to :clients
And if you do not use the alternative to this many-to-many associations with the ActiveRecord :through method (the alternative to HMABT) You must create the join table yourself which is a table of job_id's and client_id's.
I am absolutely totally news to Rails and to MongoDB. I have been following tutorials from a good book and create my first Rails app with a light Twitter copy. Everything went fine and smooth.
But as part of my learning process I wanted to build the same app using MongoDB rather than the default SGBD.
I therefore configured mongo and installed the mongo_mapper gem. Everything has been configured properly following this tutorial: http://www.mongodb.org/display/DOCS/Rails+3+-+Getting+Started. Then I struggled a little bit to allow Rails generate to work without throwing me the --orm not specified error. In order to get past this I had to add the rails3-generators gem and add it to the Gemfile.
Once all this was done, everything worked fine. I was able to successfully launch the Rails server.
I added a User controller thanks to the generate. The page works fine and even lists the users I have previously added:
However all the other actions, showing, editing, deleting, etc. are not working (creating works, but then it goes to show and the errors comes):
It's virtually the same error for all different actions.
The one difference I can notice right off the bat is that with the non MongoDB db, the id's of the user was starting at 1, etc. but here with MongoDB it looks like a randomly generated id that is much more complex and that is not of type int: 4d2ae91d4403baa84a000002
I am thinking that this may be creating the issues, since all action are using the id as a parameter... but I have no idea how to fix this. I have looked at the ruby generated code and it looks alright to me (extremely similar to the code generate for the default db).
Any help would be greatly appreciated ! I don't know how to go forward with my project without solving a simple generate code with mongodb.
Thanks,
Alex
ps:
please that I did not write any of this code at all. everything has been generated, which is kinda why I expected to work from the get go...
as asked here is the code for users_controllers:
class UsersController < ApplicationController
# GET /users
# GET /users.xml
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
end
end
# GET /users/1
# GET /users/1.xml
def show
#user = User.first(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
# GET /users/new
# GET /users/new.xml
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #user }
end
end
# GET /users/1/edit
def edit
#user = User.first(params[:id])
end
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to(#user, :notice => 'User was successfully created.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
#user = User.first(params[:id])
respond_to do |format|
if #user.update(params[:user])
format.html { redirect_to(#user, :notice => 'User was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.xml
def destroy
#user = User.first(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to(users_url) }
format.xml { head :ok }
end
end
end
Hummm so it seems I found the pb...
I replaced:
#user = User.first(params[:id])
by
#user = User.find(params[:id])
But again, this code was generated... so where does the error come from ? Is there a "bug" in rails3-generators ? Or somehow I screwed up the generation ?
Alex
respond_to do |format|
format.html
format.xml { render :xml => #mah_blogz }
end
respond_to do |format|
format.js
end
What's this respond_to, format.html, format.xml and format.js? What's their purpose and how do they work?
Here's the link to the documentation
http://api.rubyonrails.org/classes/ActionController/MimeResponds/ClassMethods.html#method-i-respond_to
Its a way of responding to the client based on what they are asking for, if the client asks for HTML, Rails will send back HTML to the client, if they ask for XML then XML.
Say you are doing this:
class UsersController < ApplicationController
def create
#
#your code
#
respond_to do |format|
format.xml {render :xml => xxx}
format.json {render :json => xxx}
format.html {render xxx}
end
end
def edit
#
#your code
#
respond_to do |format|
format.xml {render :xml => xxx}
format.json {render :json => xxx}
format.html {render xxx}
end
end
end
rather do:
class UsersController < ApplicationController
respond_to :xml, :json, :html
def create
#
#your code
#
respond_with xxx
end
def edit
#
#your code
#
respond_with xxx
end
end
and thats how you keep the code DRY (Dont Repeat Yourself)