Passing Parameters to Active Admin Table_for columns - ruby-on-rails

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]
...

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

How to make a serialized column empty?

I have a column in Company, that is serialized as Array:
class Company
serialize :column_name, Array
end
In rails console, when I try the following:
existing = Company.last.column_name
# it gives a array with single element, say [1]
existing.delete(1)
# now existing is []
Company.last.update_attributes!(column_name: existing)
# It empties the array, so:
Company.last.column_name #gives []
But, when I try the same code in remove method of some controller, it never removes the last element. It always returns [1].
How can I empty the serialized column?
NOTE:- This logic works when I have multiple elements, but doesn't work for the last element alone.
CONTROLLER CODE
def remove_restricted_num
company = Company.where(id: params[:id]).first
restricted_numbers = company.restricted_numbers
num = params[:num].to_i
if restricted_numbers.include?(num)
restricted_numbers.delete(num)
company.update_attributes!(restricted_numbers: restricted_numbers)
render js: "alert('#{num} was removed')"
else
render js: "alert('Number not found in the list')"
end
end
I got the fix, we need to use dup to get a independent variable existing, which otherwise was referencing Company.last.column_name
existing = Company.last.column_name.dup # THIS WORKS!!!
existing.delete(1)
Company.last.update_attributes!(column_name: existing)
This updates the column to [], as I need.

What is the most elegant Ruby expression for comparing and selecting values from a 2D Array?

I have some code that is chugging through a set of Rails Active Record models, and setting an attribute based on a related value from a 2D Array.
I am essentially setting a US State abbreviation code in a table of US States which was previously only storing the full names. A library of state names is being used to derive the abbreviations, and it contains a 2D Array with each sub-array having a full name, and an abbreviation (i.e., [['New York', 'NY']['Pennsylvania', 'PA'][etc]]). I compare the state name from each record in the database to each full text name in this Array, then grab the corresponding sibling Array cell when there is a match.
This code works fine, and produces the correct results, but its frumpy looking and not easily understood without reading many lines:
# For the following code, StatesWithNames is an Active Record model, which is
# having a new column :code added to its table.
# Sates::USA represents a 2D Array as: [['StateName', 'NY']], and is used to
# populate the codes for StatesWithNames.
# A comparison is made between StatesWithNames.name and the text name found in
# States::USA, and if there is a match, the abbreviation from States::USA is
# used
if StatesWithNames.any?
StatesWithNames.all.each do |named_state|
if named_state.code.blank?
States::USA.each do |s|
if s[0] == named_state.name
named_state.update_column(:code, s[1])
break
end
end
end
end
end
What is the most Ruby style way of expressing assignments with logic like this? I experimented with a few different procs / blocks, but arrived at even cludgier expressions, or incorrect results. Is there a more simple way to express this in fewer lines and/or if-end conditionals?
Yea, there is a few ifs and checks, that are not needed.
Since it is Rails even though it does not state so in question's tags, you might want to use find_each, which is one of the most efficient way to iterate over a AR collection:
StatesWithNames.find_each do |named_state|
next unless named_state.code.blank?
States::USA.each do |s|
named_state.update_column(:code, s[1]) if s[0] == named_state.name
end
end
Also be aware, that update_column bypasses any validations, and if you wish to keep your objects valid, stick to update!.
And last thing - wrap it all in transaction, so if anything goes wrong all the way - it would rollback any changes.
StatesWithNames.transaction do
StatesWithNames.find_each do |named_state|
next unless named_state.code.blank?
States::USA.each do |s|
named_state.update!(:code, s[1]) if s[0] == named_state.name
end
end
end
You might use a different data structure for this.
With your existing 2D array, you can call to_h on it to get a Hash where
a = [['California', 'CA'], ['Oregon', 'OR']].to_h
=> { 'California' => 'CA', 'Oregon' => 'OR' }
Then in your code you can do
state_hash = States::USA.to_h
if StatesWithNames.any?
StatesWithNames.all.each do |named_state|
if named_state.code.blank?
abbreviation = state_hash[named_state.name]
if !abbreviation.nil?
named_state.update_column(:code, abbreviation)
end
end
end
end
the first thing you want to do is convert the lookup from an array of arrays to a hash.
state_hash = States::USA.to_h
if StatesWithNames.any?
StatesWithNames.all.select{|state| state.code.blank?}.each do |named_state|
named_state.update_column(:code, state_hash[named_state.name]) if state_hash[named_state.name]
end
end

Loop through each element from third to last of active record object

I have active record object of array.
#obj = User.post
Now I want to loop through #obj from third element to last. I want something like below
#obj.third-to-last.each do
#output here
end
I can do this using a counter and if else condition. I want know if there is any better and simple way to do this.
Use the Array#drop method to drop the first two elements of #obj:
#obj.drop(2).each do |obj|
# whatever...
end
Just do using method ary[range] :
#obj[2..-1].each do |el|
# your code here
end

Display collection value using their attributes name

I want to display value of collection by passing their respective attribute name.
#mandates is the result of an active-record query.
#tabattributes contains array of attribute names previously selected by users.
The code below show field attributes but I want the value of these field instead.
I've tried several syntaxes but errors occurs each time.
How can I modify my code to do that?
#mandates.map do |f|
#tabattributes.each { |att| " #{att} "}
end
If #mandates is a result set that contains models with attributes a, b, and c and #tabattributes is the array %w{a b} (i.e. you want to extract a and b from each element of #mandates) then:
a = #mandates.map { |m| m.attributes.slice(*#tabattributes) }
will give you an array of hashes with keys 'a' and 'b'. For example:
#tabattributes = %w{id created_at}
slices = #mandates.map { |m| m.attributes.slice(*#tabattributes) }
# slices is now like [ { 'id' => ..., 'created_at' => ... }, ... ]
If you only want the values and don't care about the keys then perhaps this will work for you:
#mandates.map { |m| m.attributes.slice(*#tabattributes).values }
That would give you an array-of-arrays. The first array-of-hashes would probably be easier to work with though.
If you can get at #mandates before accessing the database then you could slice out just the columns you're interested inside the database with something like this:
#mandates = Mandate.select(#tabattributes)
slices = #mandates.map(&:attributes)
If I understand you right, you have an array of elements, and you want to have an array containing the name of each element, is that it ? If yes, then array.map {|elem| elem.name} should do it. There is a shorter form (array.map(&:name)) which does the same, if you're interested in how this is working, I can detail.

Resources