I want to access a newly created object inside of the conditional statement that created it:
if saved_object = Branch.new(params[:object]).save
puts saved_object.id
end
Activerecord instance save method always return true/false, so you need to initialize the object and check .save on it like below
saved_object = Branch.new(params[:object])
if saved_object.save
puts saved_object.id
end
As Naren Sisodya said, or you can use parentheses to disambiguate what is stored into saved_object (because right now saved_object holds the result of the .save call).
if (saved_object = Branch.new(params[:object])).save
puts saved_object.id
end
In this form, the saved_object variable will hold the database record and then .save will be called on that record. This is likely what you intended, but not what you got due to operator precedence rules in ruby.
Related
I have a database trigger that modifies a field on INSERT. Then when I run object.my_attribute it returns nil instead of lets say 42.
If I do object.reload.my_attribute, this is fine. But I don't want to reload the whole object or part of it unless it is necessary. And I believe code shouldn't be concerned when and how an object was created. It should just be correct.
Is it possible to mark that particular attribute as outdated and any attempt to get its value to result in a query that fetches it from database?
For example:
after_save :forget_my_attribute
def forget_my_attribute
forget_field :my_attribute
end
I think it's better to make some service object where field is modified and call it when create the record. CreateModel.call(args) instead of Model.create(args). It will be more clear than database trigger I think
But you can do something like this
after_create_commit :fetch_my_attribute
def fetch_my_attribute
self[:my_attribute] = self.class.find_by(id: id)[:my_attribute]
end
Or more flexible fetch attribute you need dynamically
def fetch_attribute(atr)
self[atr] = self.class.find_by(id: id)[atr]
end
object.fetch_attribute(:my_attribute)
I am using database to cache somedata ( in this case I don't want to use memcache,memorycache...) in rails.
I want to cache everythings (value or returned value of block in rails) , so I have some code like below
def fetch
if block_given?
result = yield
dump = Marshal.dump(result)
## some code to store dump in database
end
end
and when i call
page = fetch("key") do
MyModelInstance.where("query")
end
But I always receive a dumped of code block("MyModelInstance.where("query") ) when I store dump variable in database, not returned value of code block . I want active record model, not code block.
So is there any way to do excute code block then return value before dump in this case ? Thank
The problem is not with your fetch method, it's how you call it. yield always returns the return value of the block, not the block itself. However, active record query methods (all, where, order etc.) do not return an array of models. If they did, it would be impossible to chain them.
MyModel.where("query").order(:created_at)
# Would be "Undefined method order for array"
# if where returned an array of models
where and all the other query methods return an ActiveRecord::Relation. It behaves like an array, but it's not. This is the thing that is returned from your yield block and is being serialized.
If you want to serialize an array of models instead, call to_a on it to turn it to an array of models.
page = fetch("key") do
MyModelInstance.where("query").to_a
end
I was just trying to use
self.name = 'Tom'
inside my user model but the column does not get updated.
Using
self.update_column(:name, 'Tom')
and
update_column(:name, 'Tom')
works.
Has the first way of changing value been deprecated?
self is an object, when you do self.name = 'Tom', it just sets the new value in attribute at object level, but to save it in the database, you need to call save method on self after setting the value.
self.name = 'Tom'
self.save!
Give it a try!
self.name = 'Tom'
Calls the setter method name= that ActiveRecord generates from your columns. This just updates the object in memory and marks the attribute as changed so when you call .save or .save! the changes are persisted to the database.
Has the first way of changing value been deprecated?
No. You just completely misunderstood what it does. Using the setters has never automatically caused a database update. That would be really unexpected behavior.
self.update_column(:name, 'Tom') and update_column(:name, 'Tom') are actually the exact same thing. The first just has an explicit recipient while the later is implicit. But in both cases the recipient is self. Like its big brother the #update method this creates a UPDATE sql query.
ruby_on_rails rails 4 assignment non-screen data to insert record
Rather than using screen values (e.g. simple_form_for #user_evaluation_result) to populate the columns to insert a row I need to calculate some of the values in controller.
For example if I have these statements in the controller
….
# which if I had simple_form_for user_evaluation_result would get populated by the screen
#user_evaluation_result = UserEvaluationResult.new(user_evaluation_result_params)
….
# standard stuff I use for screen derived updates
def user_evaluation_result_params
params.require(:user_evaluation_result).
permit(:evaluation_assumption_id,
:company_listing_id,
:target_share_price_dollars )
end
How do I assign values to :user_assumption_id etc so that insert works. I have tried all sorts of statements. Alternatively do I use another format instead of calling "def user_evaluation_result_params".
Thanks in advance - Pierre
I'm hoping I've interpreted the question properly...
First, to make sure we're on the same page... The code inside of your user_evaluation_result_params method is using Strong Parameters to create an ActionController::Parameters object for the purpose of protecting your model from unpermitted mass-assignments. So, in general, when you're creating or updating an ActiveRecord object from a form in a view template, you want to use Strong Parameters so that users can't manipulate your form to set attributes that you're not expecting.
That said, if you want to set attributes on an object you don't have to use mass assignment. Here is an example of using one-at-a-time assignment (the opposite of mass-assignment):
obj = MyObject.new
obj.attr_one = "One"
obj.attr_two = "Two"
obj.save
There is nothing wrong with this approach other than that it's kind of a lot of work for the general case. So mass-assignment just saves us from having to do this all the time. But it sounds like this one-at-a-time assignment is what you're wanting in this case. So try something like this:
def create
#user_evaluation_result = UserEvaluationResult.new
# assuming you have a UserAssumption object instance in `my_user_assumption`
#user_evaluation_result.user_assumption = my_user_assumption
#user_evaluation_result.some_other_attr = "some value"
#user_evaluation_result.save
end
Note, instead of setting #user_evaluation_result.user_assumption_id directly, as you asked about, it is preferred to set the actual object association as I did above. Try to keep associations outside of mass-assignment and use object relationships to build up your object graphs.
Or, if you have some attributes coming from a form you can mix and match the two approaches:
def create
#user_evaluation_result = UserEvaluationResult.new(user_evaluation_result_params)
# assuming you have a UserAssumption object instance in `my_user_assumption`
#user_evaluation_result.user_assumption = my_user_assumption
#user_evaluation_result.some_other_attr = params[:user_evaluation_result][:some_other_attr]
#user_evaluation_result.save
end
private
def user_evaluation_result_params
params.require(:user_evaluation_result)
.permit(:evaluation_assumption_id,
:company_listing_id,
:target_share_price_dollars)
end
I saw this...
How to convert activerecord results into a array of hashes
and wanted to create a method that would allow me to turn any scoped or non-scoped record set into an array of hashes. I added this to my model:
def self.to_hash
to_a.map(&:serializable_hash)
end
However, I get this error.
NameError: undefined local variable or method `to_a' for #<Class:0x007fb0da2f2708>
Any idea?
You probably need to call all on that too. Just the to_a would work fine on a scope or existing result set (e.g. User.active.to_hash) but not directly on the model (e.g. User.to_hash). Using all.to_a will work for both scenarios.
def self.to_hash
all.to_a.map(&:serializable_hash)
end
Note that the all.to_a is a little duplicative since all already returns an array, but in Rails 4 it will be necessary.
You're performing the action on a class, not an instance of the class. You can either take away the self. then call this on an instance, or to call it on a collection you need to pass the collection into the class method:
def self.to_hash(collection)
collection.to_a.map(&:serializable_hash)
end