Skip to content
This repository has been archived by the owner on Oct 19, 2018. It is now read-only.

add to_key method to object #244

Open
catmando opened this issue Feb 9, 2018 · 2 comments
Open

add to_key method to object #244

catmando opened this issue Feb 9, 2018 · 2 comments

Comments

@catmando
Copy link
Contributor

catmando commented Feb 9, 2018

Components can be provided a key, via the special key parameter that ensures when rendering lists of components the ordering does not change, and speeds up the rendering of the list.

...
  UL do
    MyModel.each do |record|
       DisplayRecord(record: record, key: record.id)
    end
  end
...

typically you can use some data associated with the values being displayed (like record.id above) or the ruby object_id, or some other unique identifier depending on the contents of the list item.

For HyperModels (and probably other places too) this can be difficult. The above example for instance only works if all the records are saved (i.e. have ids). You can't use record.object_id since there is no guarantee that on the next rendering the record instance will be the same object_id, so you have use record.backing_record.object_id which is gross and relies on knowing the inards of HyperModel.

The solution is to add a to_key method to the base ruby Object class and to have the key parameter automatically have to_key applied to it. The default to_key method will return self.object_id, but this can be overwritten as needed. I.e. ActiveRecord::Base can override as self.backing_record.object_id.

Now we can write DisplayRecord(record: record, key: record) shorter, sweeter, and works.

Also in keeping with POLS, strings, symbols, booleans and number objects will return themselves.

class Object
  def to_key
    object_id
  end
end

class String
  def to_key
    self
  end
end

class Number
  def to_key
    self
  end
end

class Boolean
  def to_key
    self
  end
end

class Foo
end

class Bar
  def self.new_bar_counter
    @bar_counter = (@bar_counter && @bar_counter+1) || 0
  end
  def initialize
    @to_key = "Bar ##{Bar.new_bar_counter}"
  end
  attr_reader :to_key
end

puts Object.new.to_key
puts "hello".to_key
puts 12.to_key
puts true.to_key
puts Foo.new.to_key
puts Bar.new.to_key
puts Bar.new.to_key

Produces

5206
hello
12
true
5208
Bar #0
Bar #1

run it!

As well as adding the method to the classes per above, you also have to add these lines here

        elsif key == "key"
          props["key"] = value.to_key
       ...
@sfcgeorge
Copy link

This is nice. The way it's laid out is also backwards compatible because record.id or record.object_id in existing code returns a number, and Number#to_key == self.

@Donnadieu
Copy link
Contributor

Donnadieu commented Feb 17, 2018

Hi, I think I can help with this issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants