Edit: it turns out I made a very simple mistake and had a Template that was associated with a LocalTemplate id that no longer existed. If anyone has this problem and thinks that they somehow are unable to unable to associate the id of another model in their update action, make sure that you didn't accidentally delete the parent object causing that id to no longer exist! The code below, while dramatically simplified did work for me.
I have a Template model in my rails app. It has a method "data" defined in it.
I am able to access this method in the create and show actions with @template.data, however when using the same @template.data in the update action of my controller I get a no method error because I am not showing the correct local template id to it. This line can be found in the model where it reads base_data = YAML.load(local_template.data)
I stored an id of the associated local_template when initially saving a new template, but how can I make sure I reference that id again in the update action so I do not get a no method error?
Here is a simplified version of the Template model and controller
Model:
class Template < ActiveRecord::Base
def data
base_data = YAML.load(local_template.data)
# couldn't pass the correct LocalTemplate here because
# the local_template_id I had in my Template model no
# longer existed. Changing the id to a LocalTemplate
# that did exist fixed the issue.
end
end
Controller:
class TemplatesController < ApplicationController
def index
@business = Business.find(params[:business_id])
@templates = @business.templates.all
end
def new
@business = Business.find(params[:business_id])
@local_templates = LocalTemplate.all
@template = @business.templates.build
end
def create
@business = Business.find(params[:business_id])
@local_templates = LocalTemplate.all
@template = @business.templates.build(template_params)
if @template.save
@template.data #works fine here
redirect_to business_url(@template.business_id)
else
render 'new'
end
end
def show
@business = Business.find(params[:business_id])
@template = @business.templates.find(params[:id])
@template.data #works fine here too
end
def edit
@business = Business.find(params[:business_id])
@local_templates = LocalTemplate.all
@template = @business.templates.find(params[:id])
end
def update
@business = Business.find(params[:business_id])
@template = @business.templates.find(params[:id])
if @template.update_attributes!(pass_template_params)
Api.new.update_template(@template.data.to_json) #this is where I had a problem
redirect_to business_url(@template.business_id)
else
render 'edit'
end
end
end
You are mixing a lot. There is a lot to refactor in your controller...
First of all, your TemplatesController should be about the template resources, but your controller looks more like a BusinessesController. In general your update action for example should look more like:
def update
@template = Template.find params[:id]
@template.attributes = template_params # though this should raise a NoMethodError, because you dind't define it; I'd prefer params[:template] if possible
if @template.save
redirect_to business_url(@template.business_id)
else
@local_templates = LocalTemplate.all
render 'edit'
end
end
Instantiating @business and @local_templates makes non sense, because you don't use it at all. Speed up your responses if you can! :)
Fixed that, there is no need for the overhead of a nested resource in update (as you did).
If saving @template fails for validation reasons, you better should load the business object late by:
@template.business
in your /templates/edit.html.erb partial. Then you also do not need a nested route to your edit action... You see, it cleans up a lot.
As a general guideline you should create as less as possible controller instance variables.
If you cleaned up your controller and views, debugging your data issue will be easier.
I assume:
local_template
in your Template model to be an associated LocalTemplate model object. So it should no issue to call that anywhere if you ensured the referenced object exists:
class Template < ActiveRecord::Base
def data
return if local_template.nil?
YAML.load(local_template.data)
end
end
or validate the existence of the local_template object. or even b