ruby on rails: instance variable returns nil - ruby-on-rails

I've been trying to push the input data from my form to the database using the create function, but the instance variable in create function keeps returning 'nil' and after the 'begin transaction', it does 'rollback transaction'
The model function works fine as I get the desired parsed data, and so does the timetables_params function. But timetables_params[:start_time] always returns 'nil' even though the timetables_params returns all the start_time values and end_time values.
How can I fix this?
Here is my controller
def index
#user = current_user
#timetables = #user.timetable.all
end
def new
#timetable = Timetable.new
end
def create
timetables_params[:start_time] = Timetable.parse_timetable_time(timetables_params, 'start')
timetables_params[:end_time] = Timetable.parse_timetable_time(timetables_params, 'end')
#timetable = Timetable.create(timetables_params)
if #timetable.save
flash[:success] = "Done"
else
render 'new'
end
end
private
def timetables_params
params.require(:timetable).permit(:user_id, :start_time, :end_time)
end
end
Here is my model
belongs_to :user
attr_accessor :user, :start_time, :end_time
def self.parse_timetable_time(hash, type)
date_string = hash["#{type}_time(1i)"].to_s + "=" + hash["#{type}_time(2i)"].to_s + "=" + hash["#{type}_time(3i)"]
Time.parse(date_string)
end

You probably have not set the user since its belongs_to :user and i dont see it anywhere in your code. That's why its rolling back and you probably required user_id in your Timetable model. My suggestion is below
Instead of:
#timetable = Timetable.create(timetables_params)
Use build:
#timetable = current_user.timetables.build(timetables_params)

Thanks for all the help above, but turns out that I just had to add the following lines in the model and modify the controller create function:
model
validates :user_id, presence: true
validates :start_time, :end_time, presence: true
controller
def create
#timetable = current_user.timetables.build(timetables_params)
if #timetable.save
flash[:success] = "Done"
else
render 'new'
end
And, I don't necessarily need to parse the datetime values, Rails does do it automatically

Related

Ruby on Rails new() method not storing values

I have a modified copy of https://github.com/talho/openphin/blob/master/app/controllers/admin/invitations_controller.rb
The main code is primarily the same, however our system was upgraded a few months back to Rails 4.x and the invitation system no longer works.
The method with the issue is create. I have tried swapping out:
#invitation = Invitation.new(params[:invitation])
with
#invitation = Invitation.create(invitation_params)
And creating
def invitation_params
params.require(:invitation).permit!
end
However, here is what I have:
invitation_params = {"name":"Test","subject":"test","body":"test","organization_id":"","author_id":24448}
#invitation = {"id":null,"name":null,"body":null,"organization_id":null,"author_id":null,"subject":null,"created_at":null,"updated_at":null,"lock_version":0}
Also, if I use create!, then my output error is:
E, [2015-12-14T13:03:38.664099 #24385] ERROR -- : Validation failed: Author can't be blank (ActiveRecord::RecordInvalid)
I could use any guidance/help on why everything ends up as null.
You call return what leaved the method, before you call save! in the record. Furthermore you might want to read about Strong Parameters. You might want to change your code to:
#invitation = Invitation.new(
params.require(:invitation).permit(
:name, :subject, :body, :organization_id, :author_id
)
)
#invitation.save!
render :json => { :invitation => #invitation }.as_json
return
Please note that you usually do not need to call return in controller method. And when you call save! immediately after new then create! might be an better option:
def create
invitation = Invitation.create!(invitation_params)
render json: { invitation: invitation }.as_json
end
private
def invitation_params
params.require(:invitation).permit(
:name, :subject, :body, :organization_id, :author_id
)
end

Insert a record with "find_or_create_by" inside another controller fails

This is my code:
class ApplicationsController < ApplicationController
def new
#application = Application.new
end
def create
#application = Application.new(application_params)
#layout = Layout.find_or_create_by(application_id: #application.id)
if #application.save
redirect_to #application
else
render 'new'
end
end
layout belongs_to :application
When I check the Layouts table it is empty. Can you help me, please?
Your model contains the following validations:
validates :adv_path, presence: true
validates :start_time, presence: true
validates :end_time, presence: true
Therefore you are not able to create a Layout without this values. You must do something like this (with useful values):
Layout.find_or_create_by(id: #application.id) do |layout|
layout.adv_path = 'A useful default'
layout.start_time = 1.second.ago
layout.end_time = 100.year.from_now
end
Or rethink the need for the validators.
In your layout creation line, #application doesn't have an id yet. Resultantly, you pass 'nil' to the #layout's application_id which makes its validation fail. (You mentioned the layout's application presence validation in a comment).
So create the layout after #application is saved and you should be good to go.
if #application.save
#layout = Layout.create(application_id: #application.id)
When you use new method like
#application = Application.new(application_params)
it does not persist that record to db, other words it does not have id. you should use method create instead
#application = Application.create(application_params)
then #application will be persisted to db, and when you say find_or_create_by it will find with id, and not search for id nil
def create
#application = Application.new(application_params)
#layout = Layout.find_or_create_by(application_id: #application.id) # <== that line
if ...
....
end
end
That line is rather misleading. #application.id is nil. So the first time, you'll create a layout record with a application_id as nil. The next time, it'll find the record with application_id: nil and use that. So it'll just create one single record and forever use it.
If you are creating a layout every time you create an application, consider doing it this way:
def create
#application = Application.new(application_params)
if #application.save
#layout = #application.layouts.create( ... ) # assuming application has_many :layouts
redirect_to #application
else
render 'new'
end
end

Passing instance variables into API in rails

I'm trying to pass in some instance variables to call an API with that specific object's attributes. A user fills in their car details (make, model, and year) which creates an offer object. That is supposed to be passed into Edmund's API to retrieve the info for that car. The code works fine if I set it with a specific make/model/year but I can't make it return info for a created offer object.
Here's my controller:
def show
#offer = Offer.find(params[:id])
#wanted_ad = WantedAd.find(params[:wanted_ad_id])
#make = #offer.ownermake
#model = #offer.ownermodel
#year = #offer.owneryear
respond_to do |format|
format.html # show.html.erb
format.json { render json: #offer }
end
end
And here's my model:
class Offer < ActiveRecord::Base
attr_accessible :user_id, :wanted_ad_id, :estvalue, :image1, :offerprice, :ownercartype, :ownerdesc, :ownermake, :ownermileage, :ownermodel, :owneryear
belongs_to :user
belongs_to :wanted_ad
has_one :car
def self.carsearch
#car = []
carinfo = HTTParty.get("http://api.edmunds.com/v1/api/vehicle/#{make}/#{model}/#{year}?api_key=qd4n48eua7r2e59hbdte5xd6&fmt=json")
carinfo["modelYearHolder"].each do |p|
c = Car.new
c.make = p["makeName"]
return carinfo
end
end
end
My car model is simply:
class Car < ActiveRecord::Base
attr_accessible :make, :model, :year
belongs_to :offer
end
And I'm trying to call it from a view file with <%= Offer.carsearch %>. I'm probably all sorts of messed up but this is my first time working with an API and I'm very lost.
I think you got several logical errors in your carsearch method:
You're fetching a carinfo, iterate through an array, instantiate a new car but nothing happens with the c object and at the end of the first iteration you exit the whole function returning the retrieved carinfo...
Is this probably what you've meant?
def carsearch
#cars = []
# where do `make`, `model` and `year` come from here?
# probably method parameters!?
carinfo = HTTParty.get("http://api.edmunds.com/v1/api/vehicle/#{make}/#{model}/#{year}?api_key=qd4n48eua7r2e59hbdte5xd6&fmt=json")
carinfo["modelYearHolder"].each do |p|
c = Car.new
c.make = p["makeName"]
# initialize other attributes (year, model)?
#cars << c
end
return #cars
end

validation for models in ruby on rails

I have a model:
class HelloRails < ActiveRecord::Base
attr_accessible :filename, :filevalidate
include In4systemsModelCommon
validates :filename, presence: true
def update
parameters = [self.filename, #current_user]
parameters.map!{|p| ActiveRecord::Base.connection.quote p}
sql = "call stored_procedure(#{parameters.join(',')})"
ActiveRecord::Base.connection.execute(sql)
end
end
In the view I have a text_field called as :filename. When I click the submit button it calls this update method in model to call the stored proc to execute. Now validations are not working.
I dont want to accept nil for filename. How can I do this?
It doesn't validate because you are executing sql directly:
ActiveRecord::Base.connection.execute(sql)
Validations are only run when you use the "normal" ActiveRecord methods like save and update_attributes. To run validations manually you can call valid? on your object.
Model:
def update
return false unless self.valid? # validation failed: return false
parameters = [self.filename, #current_user]
parameters.map!{|p| ActiveRecord::Base.connection.quote p}
sql = "call stored_procedure(#{parameters.join(',')})"
ActiveRecord::Base.connection.execute(sql)
true
end
Then in your controller you have to check wether #object.update returns true or false and display errors in your view if necessary.
Controller:
# This is just an example. I don't know your code.
def update
#object = HelloRails.find(params[:id])
if #object.update
redirect_to somewhere
else
render :action => 'edit'
end
end

Rails: difference between attr_accessor and attr_accessible

What is the difference? Also, why does this not work:
The variables such as base_path are not being set.
class Cvit < ActiveRecord::Base
attr_accessible :species,:program,:textup,:e_value,:filter,:min_identity,:cluster_dist,:fileup_file_name
attr_accessor :base_path, :fa_file, :text_file, :dbase, :source, :bl_file, :bl_sorted, :gff_file, :cvt_file, :db, :overlay_coords_gray
def initilize(*args)
super(*args)
end
def cvitSetup()
self.base_path = "blast_cvit/"
self.fa_file = "input.fa"
.
.
end
end
in the rails console the attributes get set correctly however when I try to do this:
controller:
def show
#cvit = Cvit.find(params[:id])
#cvit.cvitSetup()
#cvit.blast()
#cvit.generateGff()
#cvit.generateCvitImage()
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #cvit }
end
end
and in my view I reference #cvit.some_attribute.html_safe but that attribute is null so I get an error. Any ideas?
attr_accessor creates the getter method.attribute and setter method.attribute= for the specified attributes.
attr_accessible is from ActiveRecord::Base and "Specifies a white list of model attributes that can be set via mass-assignment." See documentation and example here.
EDIT:
As for your second question, I don't know. I tried this dummy code and it worked:
class Test
attr_accessor :base_path, :fa_file
def cvitSetup()
self.base_path = "blast_cvit/"
self.fa_file = "input.fa"
end
end
t = Test.new
t.cvitSetup
p t.base_path
#=> "blast_cvit/"
Are you sure that you properly instantiated your class?
attr_accessor simply creates a getter-setter method for an attribute.
attr_accessible specifies a white list of model attributes that can be set via mass-assignment, such as new(attributes), update_attributes(attributes), or attributes=(attributes). This has been excerpted from the link here

Resources