I have set up 2 models in Rails:
class Category < ActiveRecord::Base
attr_accessible :name
has_many :platforms
end
and
class Platform < ActiveRecord::Base
attr_accessible :name, :url, :country
validates :name, :presence => true, :length => { :minimum => 5 }
validates :url, :presence => true, :length => { :minimum => 5 }
belongs_to :categories
end
This is my platform controller :
class PlatformsController < ApplicationController
# GET /platforms
# GET /platforms.json
def index
@platforms = Platform.all
@categories = Category.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @platforms }
end
end
# GET /platforms/1
# GET /platforms/1.json
def show
@platform = Platform.find(params[:id])
@categories = Platform.categories
respond_to do |format|
format.html # show.html.erb
format.json { render json: @platform }
end
end
# GET /platforms/new
# GET /platforms/new.json
def new
@platform = Platform.new
@categories = Category.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: @platform }
end
end
# GET /platforms/1/edit
def edit
@platform = Platform.find(params[:id])
@categories = Category.find(:all)
end
# POST /platforms
# POST /platforms.json
def create
@platform = Platform.new(params[:platform])
#@categories = Category.new(params[:name])
@categories = @platform.categories.create(params[:categories])
respond_to do |format|
if @platform.save
format.html { redirect_to @platform, notice: 'Platform was successfully created.' }
format.json { render json: @platform, status: :created, location: @platform }
else
format.html { render action: "new" }
format.json { render json: @platform.errors, status: :unprocessable_entity }
end
end
end
# PUT /platforms/1
# PUT /platforms/1.json
def update
@platform = Platform.find(params[:id])
@categories = Category.find(:all)
respond_to do |format|
if @platform.update_attributes(params[:platform])
format.html { redirect_to @platform, notice: 'Platform was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @platform.errors, status: :unprocessable_entity }
end
end
end
# DELETE /platforms/1
# DELETE /platforms/1.json
def destroy
@platform = Platform.find(params[:id])
@platform.destroy
respond_to do |format|
format.html { redirect_to platforms_url }
format.json { head :no_content }
end
end
end
I do not understand what I do wrong, but it doesnt correctly assign categories to platforms, and also in the platforms index view, when I try to use :
<%= platform.categories %>
it gives me error cannot find Category with id= “and here the respective id”
I am really confused since I followed tutorial for this one.
I use Rails 3.2.8
Without your view, I can’t say for sure what it is you’re trying to do exactly. Most importantly, what is in your params[:categories] hash? Given the name, it sounds like you intended for it to be multiple categories. However, your code is written as if you intended it to be a single set of attributes which describe one
Category.Since I can’t say for sure what you want to do, I’ll answer your question by explaining what you are doing. Maybe that will help you figure out how to fix it.
Your
createcode currently looks like this:The first line creates the new
Platformand is easy. Skipping over the comment to the third line. This is probably what’s tripping you up.You are selecting the associations for your newly created
Platformand trying to create a new category with attributes as stored in theparams[:categories]hash. I’m afraid this is not allowed. (I think it throws anActiveRecord::RecordNotSavedexception, but I could be wrong.) You can notcreateon a@platformwhich hasn’t been persisted yet. Instead, I think you wantbuild.Here is the relevant documentation:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
The difference between
createandbuildis thatbuildjust sets up the association without actually saving it to the database yet.createsaves it immediately. The nice thing aboutbuildis that you don’t actually have to save it yourself. It tags along for free when you call@platform.saveor@platform.update_attributes. Also,saveis automatically wrapped in a transaction, so it won’t create the newCategoryif it fails to create the newPlatformfor whatever reason.The next interesting thing is that you are assigning the result of your create to
@categories. I don’t think this is what you want either. You don’t need to save the newCategorybecause it tags along with your@platform. However, if thesaveof the platform fails, then you are going to re-render yournewview with this value of@categorieswhereas innewyou set@categories = Category.all. This could certainly cause some confusion on thenewview after a failedcreate.In summary, I think your
createcode should look something like the following.If you’re
params[:categories]is not a hash of category attributes and is actually a comma delimited string of category names, then you would want to do something like the following instead of my second line above:You may also want to check out
accepts_nested_attributes_forwhich can DRY out your controller even more.http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
I hope that helps.