Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add if/unless options to attribute #1266

Closed

Conversation

LcpMarvel
Copy link
Contributor

No description provided.

@LcpMarvel LcpMarvel force-pushed the add_options_to_attribute branch 2 times, most recently from 54c9151 to b8f54ae Compare October 13, 2015 03:14
attrs = attrs.first if attrs.first.class == Array

attrs.each do |attr|
attribute(attr)
attribute(attr, options)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should support any options for attributes. That's always just a list. We use attribute for an attribute with options

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want to use

attribute :id, if: :admin?
attribute :titile, if: :admin?

instead of attributes :id, :title, if: :admin? ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bf4 I'm not sure I understand why we would not want to support options for attributes. Could you elaborate?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value to end-user is minimal, cost to library is relatively high

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would usually agree, but since we already support variable number of arguments and array of symbols as parameters to attributes, I don't believe the added cost is that high.

@bf4
Copy link
Member

bf4 commented Oct 13, 2015

Thanks for this. This is a great feature! And has tests!

I personally don't think this is a good thing for AMS to support right now. I also don't think the overhead of supporting in on attributes is worth it right now. I'd be more in favor of a less invasive implementation that used a sentinel value to determine if an attributes should be excluded or a whitelist is being used., e.g. something like

attributes :banana, :tofu, :burger
def banana
  object.banana || ExcludedAttribute # can't use nil since that's a valid value
  # or 
  object.banana || ExcludedAttribute.new(:banana) # can't use nil since that's a valid value
  # or
  object.banana || :excluded_attribute
  # or 
  condition ? object.banana : :excluded_attribute
end

def tofu
  condition ? object.tofu : WhitelistedAttribute.new(object.tofu) # dunno, just thinking here
end

such that the if banana is ExcludedAttribute, attribute keys will be tofu and burger. If tofu is WhitelistedAttribute, then only tofu is a WhitelistedAttribute, then only other whitelisted attribute keys are used, so only tofu will be in the attributes. That way the feature just requires a value-check in the attributes method and the condition logic is easy to use, and maybe could lead to the suggested interface.

Also, I prefer only/except like Rails uses for this sort of thing

@bf4 bf4 added the S: Hold label Oct 13, 2015
@beauby
Copy link
Contributor

beauby commented Oct 13, 2015

Although I am currently not convinced which way is better, it seems lots of people are expecting a feature similar to this one.
@bf4, out of curiosity, how would you see an only / except system work in this case?

@bf4
Copy link
Member

bf4 commented Oct 15, 2015

@beauby you're right about only/except. I must have been thinking of something else, like fields which is a similar feature, params-driving, and is filtering only

@danhper
Copy link

danhper commented Oct 16, 2015

Would this work for associations as well? For example:

has_one :profile, if: :admin?

I think it would be more consistent to support both with the same syntax.

You want to use

attribute :id, if: :admin?
attribute :titile, if: :admin?

instead of attributes :id, :title, if: :admin? ?

%i(id title).each { |k| attribute k, if: :admin? } would do the job without having to make
the implementation more complex than it needs.

@@ -171,8 +186,31 @@ def attributes
end
end

def useless_attributes_keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

excluded_attribute_keys might be a better name here.

@beauby
Copy link
Contributor

beauby commented Oct 18, 2015

A bit more work needed, but I'm personally favorable to this implementation. People are clearly expecting such a feature, and this appears to me as the sanest way to go around it.

@bf4
Copy link
Member

bf4 commented Oct 19, 2015

IMHO, this needs to be much simpler. It introduces a lot of complexity (in understanding and maintaining the code, in addition to vectors for bugs) for what could be solved either by polymorphism or by some non-nil value that means 'remove this key'. A non-nil value that means 'include this key' is more complicated to consider.

@beauby
Copy link
Contributor

beauby commented Oct 19, 2015

The non-nil value that means 'exclude this key' puts too much of a burden on the user I think. Could you elaborate on the polymorphism solution? Do you mean subclassing the serializer into various flavors? If so, although I would personally go this way in my projects, several users have expressed their need for conditionally excluding many attributes depending on different conditions, which is a situation in which the polymorphism approach does not scale well (it takes an exponential number of serializers).

@bf4
Copy link
Member

bf4 commented Oct 19, 2015 via email

@beauby
Copy link
Contributor

beauby commented Oct 19, 2015

@bf4 True, but since this library used to do exactly that, I think we need a better reason than that.

@bf4
Copy link
Member

bf4 commented Oct 19, 2015 via email

@LcpMarvel LcpMarvel force-pushed the add_options_to_attribute branch 3 times, most recently from 255feb6 to 0436ec6 Compare October 19, 2015 03:54
@LcpMarvel
Copy link
Contributor Author

I had updated the code. 😋 @beauby

@LcpMarvel LcpMarvel force-pushed the add_options_to_attribute branch 3 times, most recently from 3043dab to bb27c7c Compare October 28, 2015 07:54
@LcpMarvel LcpMarvel force-pushed the add_options_to_attribute branch from bb27c7c to f565241 Compare November 7, 2015 06:10
@mrinterweb
Copy link

I was using the filter feature to protect attributes in my API. Now that it is gone in 0.10, is there a way to omit certain attributes? Am I supposed to have two serializers one with the attributes and one without? Should I have three serializers to replace this functionality, a base class serializer that the protected and non-protected serializers inherit from? I don't understand why we can't have filter or something like it again. Filtering out certain attributes is absolutely essential.

I need a solution to get this type of functionality back.

class UserSerializer < ActiveModel::Serializer
  attributes :id, :name, :email, :settings, :info, :token
  def filter(keys)
    unless object == scope
      keys -= [:settings, :email, :token]
    end
    keys
  end
end

If there is another way to omit keys based on the object and scope, I'd love to know. If there is no way to do this with 0.10 rc3, let me know and I'll downgrade.

@mrinterweb
Copy link

I found a solution that kind of works. My solution does not remove the attribute, but instead nullifies the value. I don't think this is a pretty solution, but it will have to do for now.

class UserSerializer < ActiveModel::Serializer

  [:email, :settings, :token].each do |a|
    define_method(a) do
      object == scope ? object.send(a) : nil
    end
  end

  attributes :id, :name, :email, :settings, :info, :token
end

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

Successfully merging this pull request may close these issues.

5 participants