How can I change serialized data using the best_in_place gem?

前端 未结 1 1257
无人及你
无人及你 2021-01-24 16:22

I have a model with serialized data and I want to edit this data using the best_in_place gem. This isn\'t possible by default when using the best_in_place gem. How

1条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-24 16:35

    It can be done by extending method_missing and respond_to_missing? to forward the requests to the serialized data. Lets say you have your serialized Hash in data. In the class that's containing the serialized data you can for example use this code:

    def method_missing(method_name, *arguments, &block) # forewards the arguments to the correct methods
      if method_name.to_s =~ /data_(.+)\=/
        key = method_name.to_s.match(/data_(.+)=/)[1]
        self.send('data_setter=', key, arguments.first)
      elsif method_name.to_s =~ /data_(.+)/
        key = method_name.to_s.match(/data_(.+)/)[1]
        self.send('data_getter', column_number)
      else
        super
      end
    end
    
    def respond_to_missing?(method_name, include_private = false) # prevents giving UndefinedMethod error
      method_name.to_s.start_with?('data_') || super
    end
    
    def data_getter(key)
      self.data[key.to_i] if self.data.kind_of?(Array)
      self.data[key.to_sym] if self.data.kind_of?(Hash)
    end
    
    def data_setter(key, value)
      self.data[key.to_i] = value if self.data.kind_of?(Array)
      self.data[key.to_sym] = value if self.data.kind_of?(Hash)
      value # the method returns value because best_in_place sets the returned value as text
    end
    

    Now you can access the object.data[:name] using the getter object.data_name and set value using the setter object.data_name="test". But to get this working using best_in_place you need to dynamicly add it to the attr_accessible list. To do this you need to change the behavior of the mass_assignment_authorizer and make the object respond to accessable_methods with an array of method names that should be allowed to be edited like this:

    def accessable_methods # returns a list of all the methods that are responded dynamicly
      self.data.keys.map{|x| "data_#{x.to_s}".to_sym }
    end
    
    private
      def mass_assignment_authorizer(user) # adds the list to the accessible list.
        super + self.accessable_methods
      end
    

    So in the View you can now call

      best_in_place @object, :data_name
    

    To edit the serialized data of @object.data[:name]

    // You can also do this for an array using the element index instead of the attribute name:

    <% @object.data.count.times do |index| %>
      <%= best_in_place @object, "data_#{index}".to_sym %>
    <% end %>
    

    You dont need to change the rest of the code.

    0 讨论(0)
提交回复
热议问题