Looping through object and blanking out fields - ruby-on-rails

I have this constant to hold all dates fields:
DATE_FIELDS = [:a_effective_on, :a_expire_on,
:field_effective_on, :field_expire_on,
:line_manager_effective_on, :line_manager_expire_on,
:officer_effective_on, :officer_expire_on,
:regional_effective_on, :regional_expire_on]
I want to loop over an object and remove a date if it has a value.
Is this valid?:
#copy_to.DATE_FIELDS.each do |_date|
# remove dates here
end
I am getting a nil class for id error.

DATE_FIELDS.each do |field|
#copy_to.send("#{field}=".to_sym, nil) if #copy_to.send(field)
end

When you put a constant in your class like this, it exists at the class level. Access it with YourClassName::DATE_FIELDS if you're outside the class, or just DATE_FIELDS if you're inside the class.
This is how i would do it:
#instance method in your class
def clear_all_date_fields
atts = {}
DATE_FIELDS.each{|f| atts[f] = nil}
self.attributes = atts
end
Now you can do
#copy_to.clear_all_date_fields
note that this doesn't save #copy_to. You can save it afterwards, or put the save into the method (though i think it's better to have it not saving automatically).

Related

Regarding attr_accessor and def initialize

I want to add school names to array using attr_accessor.
My question is what 'def initialize()' is doing in this case
so that I can store data by using
v1.school_name[0] = "myschoolname"
If I omit the initialize() function I get the error
class StoreData
attr_accessor :school_name
def initialize
#school_name = []
end
end
v1 = Store_data.new
v1.school_name[0] = "myschoolname"
print v1.school_name[0]
v1.school_name[1] = "myschoolnamehighschool"
print v1.school_name
In this case you're initializing the #school_name with an empty array. If you don't do that it doesn't automatically create it, but it could. That pattern's called lazy initialization:
class StoreData
def school_name
#school_name ||= [ ]
end
end
s = StoreData.new
s.school_name << "Name 1"
s.school_name << "Name 2"
s.school_name
#=> [ "Name 1", "Name 2" ]
You can't assign something to a nil value which is what instance variables are by default.
This one creates an array if necessary using the ||= operator.
attr_accessor is just an attribute and by default it is nil. You cannot assign any value to it. If you need it to an array then initialize it as an array before using it.

Remove current model instance from AR:Relation

I am creating an instance method on a model which returns instances of the same model. How can I ensure that the instance of the model that the method is being called upon is not part of the output?
My code is like this at the moment:
def other_versions(include_current = true)
if include_current
Coaster.where(order_ridden: order_ridden)
else
#coaster.other_version_count // Need this to exclude the current instance.
end
end
I'm not sure I understood, but would this help?
def other_versions(include_current = true)
query = Coaster.where(order_ridden: order_ridden)
query = query.where("id != ?", id) unless include_current
query
end

ActiveRecord: How to set the "changed" property of an model?

For every model in ActiveRecord, there seems to be a private property called "changed", which is an array listing all the fields that have changed since you retrieved the record from the database.
Example:
a = Article.find(1)
a.shares = 10
a.url = "TEST"
a.changed ["shares", "url"]
Is there anyway to set this "changed" property yourself? I know it sounds hacky/klunky, but I am doing something rather unordinary, which is using Redis to cache/retrieve objects.
ActiveModel::Dirty#changed returns keys of the #changed_attributes hash, which itself returns attribute names and their original values:
a = Article.find(1)
a.shares = 10
a.url = "TEST"
a.changed #=> ["shares", "url"]
a.changed_attributes #=> {"shares" => 9, "url" => "BEFORE_TEST"}
Since there is no setter method changed_attributes=, you can set the instance variable by force:
a.instance_variable_set(:#changed_attributes, {"foo" => "bar"})
a.changed #=> ["foo"]
See this example from: Dirty Attributes
class Person
include ActiveModel::Dirty
define_attribute_methods :name
def name
#name
end
def name=(val)
name_will_change! unless val == #name
#name = val
end
def save
#previously_changed = changes
#changed_attributes.clear
end
end
So, if you have a attribute foo and want to "change" that just call foo_will_change!.

How to mimic asp.net get set in rails

I am trying to mimic asp.net get{} set{} in rails, here is what i tried in my controller:
def get_segment=(segment)
if params[:s] != nil
segment = params[:s]
else
segment = "personal"
end
end
Then i am trying to access it like this:
#something = get_segment
But it always returns as nil.
How can i do this?
Thanks
Why are you using get segment=(segment)?
look like what you are wanting to do is test params[:s], so the = is uncessary, as is the segment parameter.
def get_segment
if params[:s] != nil
params[:s]
else
"personal"
end
end
I think this would give you what you want.
If you just want to mimic get{} set{} in C#, the property Segment
private string _segment;
public string Segment {
get { return _segment; }
set { _segment = value; }
}
is written as followed in Ruby:
# get
def segment
#segment
end
# set
def segment=(value)
#segment = value
end
# if you don't have additional logic, you can just write
attr_accessor :segment
Then you can use some_instance.segment to retrieve the value and some_instance.segment = some_value to modify the value.
According to your code sample above, you want to fetch s parameter with a default value if it doesn't exist. You should define a getter, not in the setter form as you have provided.
def get_segment # or just "segment"
params[:s] || "personal"
end

Using a method while looping through an array in ruby

I am using ruby-aaws to return Amazon Products and I want to enter them into my DB. I have created a model Amazonproduct and I have created a method get_amazon_data to return an array with all the product information. When i define the specific element in the array ( e.g. to_a[0] ) and then use ruby-aaws item_attributes method, it returns the name I am searching for and saves it to my DB. I am trying to iterate through the array and still have the item_attributes method work. When i don't define the element, i get this error: undefined method `item_attributes' for #Array:0x7f012cae2d68
Here is the code in my controller.
def create
#arr = Amazonproduct.get_amazon_data( :r ).to_a
#arr.each { |name|
#amazonproduct = Amazonproduct.new(params[:amazonproducts])
#amazonproduct.name = #arr.item_attributes.title.to_s
}
EDIT: Code in my model to see if that helps:
class Amazonproduct < ActiveRecord::Base
def self.get_amazon_data(r)
resp = Amazon::AWS.item_search('GourmetFood', { 'Keywords' => 'Coffee Maker' })
items = resp.item_search_response.items.item
end
end
Thanks for any help/advice.
I'm not familiar with the Amazon API, but I do observe that #arr is an array. Arrays do not usually have methods like item_attributes, so you probably lost track of which object was which somewhere in the coding process. It happens ;)
Try moving that .item_attributes call onto the object that supports that method. Maybe amazonproduct.get_amazon_data(:r), before its being turned into an array with to_a, has that method?
It's not quite clear to me what your classes are doing but to use #each, you can do something like
hash = {}
[['name', 'Macbook'], ['price', 1000]].each do |sub_array|
hash[sub_array[0]] = sub_array[1]
end
which gives you a hash like
{ 'name' => 'Macbook', 'price' => 1000 }
This hash may be easier to work with
#product = Product.new
#product.name = hash[:name]
....
EDIT
Try
def create
#arr = Amazonproduct.get_amazon_data( :r ).to_a
#arr.each do |aws_object|
#amazonproduct = Amazonproduct.new(params[:amazonproducts])
#amazonproduct.name = aws_object.item_attributes.title.to_s
end
end

Resources