Subtraction in Rails - ruby-on-rails

I have an object that has an integer type of attribute. I want to subtract 1 from the attribute after a particular action. I tried in the controller:
def subtraction
#find a item and get the value, let's say value is 40
item = Item.where(id: params[:id]).pluck(:value)
# subtract 1 from the value and i thought it would be 40-1
after_subtraction = item.to_i - 1
#update the value
final = item.update(value: after_subtraction)
end
I get:
NoMethodError (undefined method `to_i' for [40]:Array
When I remove to_i, it says - is not a method. Is there any way to update the stored value?

The better way to handle is
item = Item.find_by(id: params[:id]).value
pluck will return you array, which is not necessary in your case here.

Based on the way you constructed the query, it gets the value for all entries that match the where condition, hence what is returned by the .pluck method is an array on which you cannot call .to_i method.
I guess what you want to do is to pluck the value you need from the first entry that matches your query, hence you can refactor as below
def subtraction
#find the first item with id supplied
item = Item.where(id: params[:id]).first
#after subtraction value
val = item.value - 1
#update the value
final = item.update(value: val)
end

As pluck returns an array you can not use to_i for conversion here.
Seeing your code, you can refactor it like this,
def subtraction
# Find the item first
item = Item.find(params[:id])
# Subtract 1 from the value column of the item
item.value -= 1
# Save the modification of the item
item.save!
end

You can't directly convert array in to to_i . please use below method
after_subtraction = item.join.to_i - 1
Yes, Nithin's answer is more valid. you can go with nithin's answer. you don't need to use pluck until you want array of multiple values.

Related

Sort a returned object by its boolean parameters [Ruby]

i think i used the right terminology for what i need, i currently have a database call in my home_controller that is returning a call to my database with all the entries in that table specified, Freelancer.
There is an attribute on these records that has either a true or false value, which is "featured".
I need a way to call a sort method, or some other way, on that object with the true being first and then the false being afterwards, i tried using this code
def index
#freelancers = Freelancer.all
p 'below im outputting featured freelancer i hope'
#freelancers.sort_by { |row| [row.featured ? 0 : 1, row.id]}
p #freelancers
end
But unfortunately this did not work, can anyone advise me on a way to get this to work? Id rather have the sorted object returned as is, rather then assigning it to a new one. Just for future features of adding pagy and a filter by cost.
Use order method
def index
#freelancers = Freelancer.order(featured: :desc)
end

Converting array with .join not saving value

I have a method do_stuff that takes a string as a value. However, an array of two strings is occasionally passed in. In this situation, I need to convert the array to a single string (without commas). So for example, ["hello", "world"] should become "hello world".
So, if value = array, join the two strings, otherwise leave it alone.
The following line I have does what I want, but I am struggling with actually "saving" the value before passing it to the method do_other_stuff.
def do_stuff(value)
value.join("") if value.is_a? Array
do_other_stuff(value)
end
So I think i am close, but what would be the best way to ensure value is manipulated before passing it to do_other_stuff ?
join does not change your object, you're wasting its return value
value = value.join if value.is_a? Array
Note that "" is the default for the join parameter, so I got rid of it
Replace
value.join("") if value.is_a? Array
With
value = value.join("") if value.is_a? Array
Basically you need to reassign result back to value
Use duck typing instead of checking the class:
def do_stuff(value)
do_other_stuff(value.try(:join, '') || value)
end
.try is from ActiveSupport and will return nil if the object does not respond to the method. In plain old ruby you would write this as:
def do_stuff(value)
do_other_stuff(value.respond_to?(:join) ? value.join("") : value)
end

Passing Parameters to Active Admin Table_for columns

I'm trying to set up a table_for in my active admin project which displays information based on methods I pass to it. I'm setting it up so that in the model, there is an array of arrays. The arrays within the array contain first the label, then the method meant to be run in the column. I'm trying to set it up this way:
panel "Acquired Shares" do
table_for shareholder.acquired_shares_transactions do
shareholder.acquired_shares_info.each do |section|
column (section[0]) { |transaction| section[1] }
end
end
end
Here is the code of the method which returns the array of arrays:
def acquired_shares_info
data = [[:label, transaction.event.to_s], [:amount_of_shares, transaction.amount_of_shares],
[:share_price, transaction.event.share_price],
[:total_price, (transaction.amount_of_shares * transaction.event.share_price)],
[:occurred_on, transaction.event.occurred_on],
[:from_shareholder, transaction.event.from_shareholder],
[:share_transaction_action, transaction.event.share_transaction_action.name],
[:share_transaction_type, transaction.event.share_transaction_type.name]]
return data
end
This is all is meant to create a column for each label and method I specify in the array. However, I am stuck on how to pass the labels and methods from the array into the column for the table. The way that I try here keeps throwing the error "No block given" on the array. Anyone have ideas on how to set this up?
Thank you!
Defer evaluation of the method by wrapping it in a proc. Pass the proc as the last parameter instead of specifying a block, Ruby will substitute it for you.
data = [[:label, proc { |transaction| transaction.event.to_s }], ...
...
column section[0], section[1]
...

Rails: trying to store particular column value in an array

I am building an application in rails, and I have an items_controller which contains the methods application for create, show, edit, destroy etc.
However, I am trying to create my own method to access all the values in a specific column of my database and I am having greatly difficulty in capturing this data in an array.
I have tried the following ways of capturing the data (where 'quantity' is the column in the database for which I looking for):
#items = Item.find(params[:id])
#items2 = #item.find(params[:quantity])
I have also tried:
#items = Item.find(params[:quantity])
& even:
#items = Item.all
#items2 = #item.find(params[:quantity])
However, none of these methods appear to be working. For what I am doing it is not even essential to
know which quantity column values relate to which row...just getting a list of the column values would suffice.
If any one knows what is wrong here, the help you be very greatly appreciated!
Thanks.
UPDATE:
For clarity I am trying to retrieve all the data for a particular column in my database associated with the items_controller and filter the data for a particular piece of data (in this case the string "7" - as the data is returned from the db as a string when using the Items.all method.
I then want a counter to increase each time the "7" is encountered in the quantity column.
def chartItems
#items = Item.find(params[:id])
#items2 = #items.find(params[:quantity])
#filter = custom_filter_for(#items2)
def custom_filter_for(value)
j=0 # counter initialised at 0
value.each do |x|
if x == "7" # checking for data equal to "7" - the num is retrieved as a string
j = j+1 # increase j counter by 1 whenever "7" is encountered as a quantity
end
return j
end
end
Your find parameter is handled as an id in this case:
#items = Item.find(params[:quantity])
All items are returned which has the id of your quantity parameter. This is clearly not what you want.
You can select Items based on quantity:
#items = Item.find_by_quantity(params[:quantity])
But if you need only the quantities in an array, this is what you are looking for:
#quantities = Items.select(:quantity).map(&:quantity)
Your updated question:
result = Items.find_by_quantity(params[:quantity]).count
In new versions of ActiveRecord, they've added the pluck which does essentially what #Matzi's select and map method does.
To get all item quantities, you could do
#quantities = Item.pluck(:quantity)
Also, I would double check your use of the find_by helpers. I think that find_by_quantity will only give you a single match back (#item, not #items). To get all, I think you really want to use where
#quantities = Item.where(:quantity => params[:quantity])
If you were to use the pluck I mentioned above, I think your filtering step could also be written pretty concisely. That filter is simply counting the number of 7's in the list, right?
#quantities = Item.pluck(:quantity)
#filtered_values = #quantities.select{|q| q == 7}.length
I hope this helps out.

Ruby / ROR assignment using or (Default values for checkbox)

I am trying to assign a default value to a check box in ROR. The following is the heirachy:
Check if value is in the params (url querystring)
Check if it's in the session variable
If neither, default to all possible values and set #rates to all possible values
I have written the following code:
#all_rates = Rates.all_rates
rates_all = {}
#all_rates.each {|rate| rates_all[rate] = "1"}
p rates_all
#rates = params[:rates] ||= session[:rates] ||= rates_all
puts #rates.length, #rates
when i p rates_all, i get the hash back, however when i check #rates.length it is not being assigned i get a 0.
Did you check if params[:rates] is nil? Because if it's an empty hash then it's still an object, just without any values. But the empty hash object would be assigned to #rates anyway, resulting that rates is an empty hash object too, with length 0.
Give this a try:
#rates = case
when params[:rates].present?
params[:rates]
when session[:rates].present?
session[:rates]
else
Rates.all_rates.inject({}) { |hsh, rate| hsh.merge(rate => '1') }
end
Sidebar:
Your model name should be the singular Rate. The ||= syntax in your example is invalid. It should be just ||.

Resources