why does klass.create(donor) always create a new donor while donors_controller#create does not - ruby-on-rails

When I go to my donors_controller#create from a form in my view, it will update a record if it matches on ID or the collection of columns in my find_by_*
But if I call that create from a different controller, it always creates new records.
My donors_controller has a create method with:
def create
# need to find donor by id if given, else use find_or_create_by_blahblahblah
unless #donor = Donor.find_by_id(params[:donor][:id])
#donor = Donor.find_or_initialize_by_company_and_prefix1_and_first_name1_and_last_name1_and_address1(params[:donor])
end
if #donor.new_record?
...
else
...
end
end
My other controller has :
class_name = 'Donor'
klass = ActiveRecord.const_get(class_name)
... code to populate myarray with appropriate values
klass.create(myarray)
I am pretty sure myarray is populated with the necessary params since it creates valid records with everything in the right place. I can even run the same record through more than once and it creates duplicate (except for the Donor.id of course) records.
What am I doing wrong here?
I noticed I could do this in my other controller and it works, but why can't I call the create from the donors_controller and have it work without always creating a new record?
#klass.create(myarray)
#mydonor = klass.find_or_initialize_by_company_and_prefix1_and_first_name1_and_last_name1_and_address1(myarray)
#mydonor.save

your question is very unclear and hard to follow, so i'm not sure my answer will match your needs. It seems you're confusing a controller#create method with a model#create method.
On the model : it is a class method
create, as its name implies, instantiates a new object of the Donor class and calls save on it:
#donor = Donor.create
# is the same thing as
#donor = Donor.new
#donor.save
Active Record uses new_record? to determine if it should perform an insert or an update on the db when you call save on an instanciated record. So with create it will always be an insert since the record is inevitably new ; but if you call save on a record retrieved from the database, it will be updated.
On a controller : it is an instance method
... but does not directly manages persistence, that's the role of the model. It is an action for this controller ; it is called create for the sake of RESTful naming conventions. create is called on a controller instance when a POST request is routed to it ; its purpose is to manage that request, which often (but not always) means to create records using the appropriate model, using YourModelName.new or YourModelName.create.
so it is absolutely possible (but not advisable) to do:
class DonorsController < ApplicationController
def create
# only works well if params[:donor][:id] is nil,
# will raise an error if a record with the
# same id exists in the database
#donor = Donor.create(params[:donor])
end
end
as it is generally needed to perform several operations before saving your record, and to check if save is successful, the process is broken down :
class DonorsController < ApplicationController
def create
#donor = Donor.new(params[:donor])
# perform operations on #donor (instance of Donor class)
if #donor.save # save returns true if successfully performed, false either
# all is fine
else
# #donor could not be saved
end
end
end

Related

How to implement controller in order to handle the creation of one or more than one record?

I am using Ruby on Rails 4.1. I have a "nested" model and in its controller I would like to make the RESTful create action to handle cases when one or more than one records are submitted. That is, my controller create action is:
def create
#nester = Nester.find(:nester_id)
#nesters_nested_objects = #nester.nested_objects.build(create_params)
if #nnesters_ested_objects.save
# ...
else
# ...
end
end
def create_params
params.require(:nesters_nested_object).permit(:attr_one, :attr_two, :attr_three)
end
I would like it to handle both cases when params contain data related to one object and when it contains data related to more than one object.
How can I make that? Should I implement a new controller action (maybe called create_multiple) or what? There is a common practice in order to handling these cases?
Well, if you insist on creating those records aside from their nest, I can propose to go with something like this (it better be a separate method really):
def create_multiple
#nest = Nester.find(params[:nester])
params[:nested_objects].each do |item|
#nest.nested.new(item.permit(:attr_one, :attr_two, :attr_three))
end
if #nest.save
....
else
....
end
end

RUBY ON RAILS-Get user input to insert into database,process it, insert new variable into database

User is required to input a name (that will insert into database) and I need the user input name to use in another function to process then I need the newly processed input to insert into database.
So far, i manage to do is:
A name inserted into database
-> I saved it (name = personname, nameJob = nil)
-> I update_attribute('nameJob', nameJob_func(params[:name]))
Is there a better way where I can insert both entries together into the database after I process the nameJob_func()?
You can create a before_save callback which performs the nameJob_func() function. You therefore never need to call it explicitly, as Rails will call it just before the object is saved. Only the input name needs to be dealt with.
YourModel < ActiveRecord::Base
# Register nameJob_func as a callback
before_save :nameJob_func
private
def nameJob_func
# Do something with self.name
self.nameJob = 'something you made here with #{self.name}'
# This value will get saved to the database automatically
end
end
Now, whenever the object calls .save(), nameJob_func() runs and gets its updated value from :name.
YourModelsController < ActionController::Base
def create
#yourobj = YourModel.new(params[:name])
# The callback is called and then the whole thing gets saved
#yourobj.save
end
end

Rails :before_save, either create or update record and return false?

Have a form that has 1 field, an email address.
When submitted the model calls :before_save
Checks to see if the email address exists.
If it does, it creates a new record.
If it does not, it updates a record in another model AND NO record should be created.
Using return false to cancel the before_save for 2.2 but it rolls back the update and cancels the creation where I just want the record not to be created.
Am I on the right path? Is there a better way?
It is strange that you got user A's object, but update user B's row......
Maybe you could find the correct user object in the controller first:
#user = User.find_by_email(params[:email]) || User.new(params[:email])
User.find_by_xxx would return nil if it cannot find the corresponding object (or return the first object if there are two or more objects matched).
You could just make your own before_save method equivalent and call that instead of object.save
eg.
def custom_save
if email_address_exists? # this would be a method you create
self.save
else
# update record in other model
end
end
Then in your controller use this instead of save (ie. model.custom_save)

Existing Rails model without fetching it from the database

Does anyone know if its possible to create a model instance and apply the ID and any other attributes without having to load it from the database? I tried doing this, but the associations are not fetched from the database :( Any ideas?
EDIT
What I want to accomplish is simply this:
Fetch an existing record from the database.
Store as "hashed" output of the record into redis or some other memory store.
Next time when that record is fetched, fetch the cached store first and if it is not found then goto step 1.
If there is a cache hit, then load all the cached attributes into that model and make that model instance behave as if it were a model fetched from the database with a finite set of columns.
This is where I am stuck, what I've been doing is creating a Model.new object and setting each of the params manually. This works, but it treats the instantiated model object as a new record. There has got to be an intermediate subroutine in ActiveRecord that does the attribute setting.
I solved the problem by doing the following.
Create a new model class which extends the model class that I want to have cached into memory.
Set the table_name of the new class to the same one as the parent class.
Create a new initialize method, call the super method in it, and then allow a parameter of that method to allow for a hash variable containing all the properties of the parent class.
Overload the method new_record? and set that to false so that the associations work.
Here's my code:
class Session < User
self.table_name = 'users'
METHODS = [:id, :username] # all the columns that you wish to have in the memory hash
METHODS.each do |method|
attr_accessor method
end
def initialize(data)
super({})
if data.is_a?(User)
user = data
data = {}
METHODS.each do |key|
data[key] = user.send(key)
end
else
data = JSON.parse(data)
end
data.each do |key,value|
key = key.to_s
self.send(key+'=',value)
end
end
def new_record?
false
end
end
The memcached gem will allow you to shove arbitrary Ruby objects into it. This should all get handled for you transparently, if you're using it.
Otherwise, take a look at ActiveRecord::Base#instantiate to see how it's done normally. You're going to have to trace through a bunch of rails stack, but that's what you get for attempting such hackery!

Base.save, callbacks and observers

Let us say that we have the model Champ, with the following attributes, all with default values of nil: winner, lose, coach, awesome, should_watch.
Let's assume that two separate operations are performed: (1) a new record is created and (2) c.the_winner is called on a instance of Champ.
Based on my mock code, and the observer on the model, what values are saved to the DB for these two scenarios? What I am trying to understand is the principles of how callbacks work within the context of Base.save operation, and if and when the Base.save operation has to be called more than once to commit the changes.
class Champ
def the_winner
self.winner = 'me'
self.save
end
def the_loser
self.loser = 'you'
end
def the_coach
self.coach = 'Lt Wiggles'
end
def awesome_game(awesome_or_not=false)
self.awesome = awesome_or_not
end
def should_watch_it(should=false)
self.should_watch = should
end
end
class ChampObserver
def after_update(c)
c.the_loser
end
def after_create(c)
c.the_coach
end
def before_create(c)
c.awesome_game(true)
c.should_watch_it(true) if c.awesome_game
end
end
With your example, if you called champ.winner on a new and unmodified instance of Champ, the instance of Champ would be committed to the DB and would look like this in the database:
winner: 'me'
awesome: true
should_watch: true
loser: nil
coach: nil
The after_create callback would be called if it is a new record, and if not, the after_update callback would (this is why loser would be nil if the instance was new). However, because they just call a setter method on the instance, they will only update the instance and will not commit more changes to the DB.
You could use update_attribute in your observer or model methods to commit the change, but unless you actually need to have the record in the database and then update it, it's wasteful. In this example, if you wanted those callbacks to actually set loser and coach in the database, it'd be more efficient to use before_save and before_create.
The Rails guides site has a good overview of callbacks here, if you haven't read it already.

Resources