I am using an input field with a collection, which is drawn from an array in the model. This works well, but I would like to return a different value to the actual column in the table. I'm using simple_form.
model
TASK_OPTIONS = %w(Detection Cloning Sequencing Primer_List Primer_Check)
view
<%= f.input :primer_task, :collection => Primer3Batch::TASK_OPTIONS, :label => 'Task' %>
I might want to return something like this:
{1 => 'Detection', 2 => 'Cloning'... etc
Or this:
{'AB' => 'Detection, 'C' => 'Cloning' ....
That is: the page will display Detection, Cloning etc but the database column will store 1,2 or AB, C
I've guessed it can be done with a hash but I can't quite work out the syntax.
a = []
%w(Detection Cloning Sequencing Primer_List Primer_Check).each.with_index(1) do |it,ind|
a << [ind,it]
end
Hash[a]
# => {1=>"Detection",
# 2=>"Cloning",
# 3=>"Sequencing",
# 4=>"Primer_List",
# 5=>"Primer_Check"}
Using Enumerable#each_with_object
a = %w(Detection Cloning Sequencing Primer_List Primer_Check)
a.each_with_object({}) {|it,h| h[a.index(it) + 1 ] = it }
# => {1=>"Detection",
# 2=>"Cloning",
# 3=>"Sequencing",
# 4=>"Primer_List",
# 5=>"Primer_Check"}
Related
I know that if you have an array and reference it as array.uniq it will return without any of the duplicates.
However in this case it is an array of objects (is that proper ruby speak?). I want each call to go into the #calls array unless the call.from is the same as a call_formatted object already present in the array.
How can I conditionally place these objects in the array if no other objects in the array have the same call.from value?
calls_raw.each do |call|
call_formatted = {
:date => date,
:time => time,
:from => call.from,
:duration => call.duration,
:recording => recording,
}
#calls << call_formatted
end
array.uniq { |item| item[:from] }
Use #map to build your array for you and call #uniq on it...
calls_raw.map do |call|
{
:date => date,
:time => time,
:from => call.from,
:duration => call.duration,
:recording => recording,
}
end.uniq{|call| call[:from]}
The above approach will first build an array of calls larger than it may ultimately need to be, and the final call to #uniq will make the list unique.
Or, to avoid adding all the duplicates in the array, you could build it with a Hash as such:
calls_raw.each_with_object do |call, h|
h[call.from] ||= {
:date => date,
:time => time,
:from => call.from,
:duration => call.duration,
:recording => recording,
}
end.values
The Hash approach will use the first occurrence of call.from as it is being set with ||=. To use the last occurrence of call.from then use a straightforward assignment with =.
It's also been suggested to just use a Set instead of an Array.
To take that approach you're going to have to implement #eql? and #hash on the class we're populating the set with.
class CallRaw
attr_accessor :from
def initialize(from)
self.from = from
end
def eql?(o)
# Base equality on 'from'
o.from == self.from
end
def hash
# Use the hash of 'from' for our hash
self.from.hash
end
end
require 'set'
s = Set.new
=> <Set: {}>
s << CallRaw.new("Chewbaca")
=> <Set: {<CallRaw:0x00000002211888 #from="Chewbaca">}>
# We expect now, that adding another will not grow our set any larger
s << CallRaw.new("Chewbaca")
=> <Set: {<CallRaw:0x00000002211888 #from="Chewbaca">}>
# Great, it's not getting any bigger
s << CallRaw.new("Chewbaca")
s << CallRaw.new("Chewbaca")
=> <Set: {#<CallRaw:0x00000002211888 #from="Chewbaca">}>
Awesome - the Set works!!!
Now, it is interesting to note that having implemented #eql? and #hash, we can now use Array#uniq without having to pass in a block.
a = Array.new
a << CallRaw.new("Chewbaca")
=> [<CallRaw:0x000000021e2128 #from="Chewbaca">]
a << CallRaw.new("Chewbaca")
=> [<CallRaw:0x000000021e2128 #from="Chewbaca">, <CallRaw:0x000000021c2bc0 #from="Chewbaca">]
a.uniq
=> [<CallRaw:0x000000021e2128 #from="Chewbaca">]
Now, I'm just wondering if there is a badge that StackOverflow awards for having too much coffee before setting out to answer a question?
Unless there's some reason it has to be an array, I'd store the data in a Hash, keyed by the from value.
Then it's easy and fast to look up an entry by the from value. You can choose to insert a new value only if there's no value already with the same key, or insert the new value and let it replace the old entry with that key.
Example:
calls = Hash.new
def add(call)
if not calls[call.from]
calls[call.from] = call
end
end
Is there a way to compare two instances of model like
Model.compare_by_name("model1", "model2") which would list the differing column fields
You can use ActiveRecord::Diff if you want a mapping of all the fields that differ and their values.
alice = User.create(:name => 'alice', :email_address => 'alice#example.org')
bob = User.create(:name => 'bob', :email_address => 'bob#example.org')
alice.diff?(bob) # => true
alice.diff(bob) # => {:name => ['alice', 'bob'], :email_address => ['alice#example.org', 'bob#example.org']}
alice.diff({:name => 'eve'}) # => {:name => ['alice', 'eve']}
There is no standard comparator for this. The standard ActiveModel comparator:
Returns true if comparison_object is the same exact object, or comparison_object is of the same type and self has an ID and it is equal to comparison_object.id.
You can write your own by using Hash#diff from activesupport. Something like the following should hopefully get you started:
def Model.compare_by_name(model1, model2)
find_by_name(model1).attributes.diff(find_by_name(model2).attributes)
end
Without using a library or defining a custom method, you can easily get a diff between two models.
For instance,
a = Foo.first
b = Foo.second
a.attributes = b.attributes
a.changes #=> {"id" => [1,2] }
I am using Ruby on Rails 3.0.7 and I would like to know how to initialize\build "custom" data structures responding to the where method as like it works, for example, for common RoR AssociationCollection objects.
For example:
# The following code should work after build the 'test_data' as well...
# but how to build that?
test_data.where(:test_attribute => 'test_value')
I'm not entirely clear on what you're after, but you could create a wrapper around (for example) an array of hashes that used where to do searching.
class Search
def initialize(data)
#data = data
end
def where(filters={})
#data.select do |item|
filters.all?{|key, value| item[key] == value }
end
end
end
data = [
{ :name => 'Sam', :age => 27, :gender => 'M' },
{ :name => 'Sue', :age => 27, :gender => 'F' },
{ :name => 'Bob', :age => 32, :gender => 'M' }
]
search = Search.new(data)
search.where(:age => 27) # returns array containing Sam and Sue hashes
search.where(:gender => 'M') # returns array containing Sam and Bob hashes
search.where(:age => 27, :gender => 'M') # returns array containing just Sam
How can I change this :project_pages_id => 1 value to auto increment?
user.projects.create!(:title => Faker::Lorem.sentence(1), :project_pages_id => 1)
10.times do |n|
user.projects.create!(:title => Faker::Lorem.sentence(1), :project_pages_id => n
end
You'd need to iterate over an array like:
a = (1..10).to_a #or however many ID's you want.
a.each do {|d| user.projects.create!(:title => Faker::Lorem.sentence(1), :project_pages_id => d)}
I'm sure there is other ways, but this is quick and dirty, and it's only a test.
Is that project_pages_id intended to be a foreign key? If so, why would you auto-increment it such that it will have a nil association?
It looks like you're trying to create seed data. A good way to do that is to use Factory Girl:
https://github.com/thoughtbot/factory_girl
Among other things, it has the concept of "sequences", which solves your original question:
# Defines a new sequence
Factory.sequence :email do |n|
"person#{n}#example.com"
end
Factory.next :email
# => "person1#example.com"
Factory.next :email
# => "person2#example.com"
Schema:
action_types
------------
id
name
description
actions
-------
id
action_type_id
date
description
The goal is to copy action_types.description to actions.description only if it is not occupied yet on the UI (!).
What is done:
class ActionsController < ApplicationController
active_scaffold :action do |c|
c.columns = [ \
, :date \
, :action_type \
, :description \
]
c.columns[:action_type].form_ui = :select
c.columns[:action_type].options[:update_column] = :description
c.columns[:description].form_ui = :textarea
c.columns[:description].options = { :cols => 40, :rows => 5}
end
protected
def after_render_field(record, column)
# record: almost empty, only "action_type" is filled.
# column: column.name == "action_type"
# #params[]: id: id for the record
# But no data on UI state. So if the user wrote some lines into the
# description then it will be lost. No possibility
# to express "do nothing!"
end
#...
end
Alternatively I can accept if we do not have this functionality during "update" only on "create". Which is a half measure, but will be enough for now.
Any ideas?
(Rails 2.3.4)
Up-vote and accept for them:
http://markmail.org/message/cfbhmeyfjw3bjisp#query:+page:1+mid:vnnrbzdj7cywlvgm+state:results
You can copy javascript_for_update_column method into your helper file, and change :with to "Form.serialize(this.form)" (from "'value=' + this.value").
In after_render_field method you can use:
update_record_from_params(record, active_scaffold_config.update.columns, params[:record])
FYI: Empty fields are coming as nils, not empty strings.