-
-
Notifications
You must be signed in to change notification settings - Fork 76
Custom Attributes #108
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
Custom Attributes #108
Conversation
Howdy! Thank you for this. I tried to get it up and running locally to check out how things looked and functioned, but couldn't get it running properly (couldn't create content, and edit forms after creating content on the console were blank). That said, this sounds like just what we're looking for to finish #92. I'm not sure I understand the relation between AttributeCategories and AttributeFields, though. Do content (characters, locations, items, and universes) have many AttributeCategories (and therefore many AttributeFields through AttributeCategories), or do they merely have many AttributeFields (and, if the former, why not the latter)? As for conforming to existing paradigms, I think we could (and should) do away with just doing Thanks again for doing this! This is a hugely requested feature, and I'd love to see it materialize in a nice way. :) |
Thanks for checking it out. I agree, using the existing forms right now is pretty broken. I'll sort that out and when I get back to this. I started off with a user just having many attribute fields, but I soon hit a problem of "where does the field go?" when displaying it on a resource. That led me to groupings of attributes, which i called categories, because this ends up almost directly mapping
There are some fields on a resource that I'd want to make sure are on there regardless of how they configure the attribute fields. Those "system fields" will probably be mostly relationships and core stuff like description. I'm thinking this PR will be in addition to many columns that could eventually be replaced by this PR, but I think that's outside the scope here. Lastly, regarding the value of an attribute. I think it could be pretty easy to obtain the values for a resource given that resource's attribute fields. I'm mainly concerned about n+1s and making sure updating and fetching those attributes is performant. This is the main reason why attribute fields are denormalized and contains user_id. |
@mwerner Oh hey, I just saw the above! Thanks for the response. I think your description of AttributeCategories and AttributeFields makes sense. Moving them to models and in the DB opens up showing/hiding them dynamically, which is also something some users have requested, so I think it's a good idea and you've got a good implementation of it here (and I'd love to see the hard-coded hashes in every model go away!). Good idea on the system fields as well. Also, yeah, being performant is pretty important here, especially with the scaling of users we've seen since launch. Once you've got something working, I'd be happy to roll through the code and look for any optimizations I could make as well. I bet we could nail performance with a few passes. Also, gems like bullet are very useful locally for finding and fixing n+1's, if you haven't seen it already 👍 |
Cleaned it up quite a bit. There are a few more things to consider:
I'm sure there are some other nuanced stuff like the question box in the sidebar and how these new |
This is absolutely awesome (and thanks for the gif)! Some notes on cleaning up the
It looks great so far though! I'm pretty sure this is one of the most-frequently-requested features. I'll take a look through the code now and first thing in the morning and see if I've got any comments as well. Thanks again! |
<div class="row"> | ||
<div class="col s4"> | ||
<h2>Characters per user</h1> | ||
<%= column_chart User.joins(:attribute_fields).group(:user_id).count().group_by { |n| n.last }.each_with_object({}) { |(content_count, ids), h| h[content_count] = ids.count } %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, this info is a bonus! Thanks!
I don't know why the Travis build won't start, but it doesn't even appear in the build history so I can't force-restart it. If you could try merging master into your fork, then push again, that would probably get the build to go through. |
Unfortunately I'm going to be without internet for about a week or so. Feel free to hack on this branch if you like, otherwise I'll take a look at this when I get back. |
I didn't get a chance to dig as much into this branch as I'd hoped this week, but I'm going to finish up the relations on #133 and then try to dig in deep and get it merged into the |
That looks fantastic! The options drop-down is the perfect place for the feature, and I think the ability to create a new tab like that will be very appreciated. Also I love the refactor as a whole, it takes the app in a really good direction. |
@mwerner That looks almost exactly as how I was picturing it working, except even cleaner. Very awesome (except for the spoilers!). I think with a way to delete these fields, this could ship as-is and it'd provide a huge amount of value for all users. Is there anything other than that you were looking to add? |
How to delete the categories/fields is a good question. I'm not sure the best place to provide that functionality. Any thoughts? |
How about a small X icon at the top-right corner of each attribute field? |
What about putting it in a three dot dropdown to the right of the field. That would make it easy to add extra functions in the future (e.g. attribute privacy). |
I think a three-dot dropdown is the best approach here. Also opens us up to do other manipulations as @mpigsley says, like adjusting per-field privacy (requested by users), being able to edit single fields without loading the whole edit page (requested by users), and other small things. Could probably also throw in an edit link in that dropdown eventually so users could fix things like field typos in the same modal instead of having to delete and re-add fields. Speaking of deleting fields, just to clarify @mwerner: if you delete a field with data in it, does that data disappear for all content using that field? |
The way it's written now, I'm grabbing all the attribute categories created by the current user for the current entity (Character, Location, etc). For each of those categories, I render the given field. So that means, if there are attribute values for that resource, they won't display. I think that could be changed without too much difficulty since the actual value itself is separate from the attribute field, but as it is right now, it just wouldn't show up. I'll see what I can do about the per-field dropdown when i get some time to work on it tonight. |
I think that's alright, just wanted to scope out what the interaction was there. I would assume since they value and field are separate, that re-adding a deleted field with a value would actually being that value back? I think that's okay too. Since this is branched off the Again, great work! This is awesome, and something I can't wait to get out to everyone. 👍 |
:icon: info | ||
:attributes: | ||
- :name: name | ||
:label: Name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a showstopper, but I think the labels here are redundant with our internationalization en.yml (config/locales/en.yml). We'll probably want to eventually replace whatever uses these labels with the logic of:
- If I18n.translate('characters.attributes.name') exists, use the label there
- Otherwise (as I imagine would be the case for custom fields), just titleize the name here into a label
I think that'd let us have pretty sane defaults here without needing to specify a label for everything, while still allowing (language-agnostic) overrides that we can translate to the user's language. @Cantido Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, but since these values are no longer part of the ActiveModel object, I'm not sure how to leverage that machinery.
I think the yaml files were just a way for me to clear up I also added some specs. I'm pretty happy with the state of the PR if you guys are. I think the only outstanding stuff is:
|
|
||
<ul id="attribute-field-menu-<%= field.id %>" class='dropdown-content'> | ||
<li> | ||
<%= link_to "Delete this attribute forever", field, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be internationalized? Same with the confirmation below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should be, but this is the only place I've seen in the repo that is doing any internationalization. I took this from actions_dropdown which isn't internationalized either. I think those types of changes should be done in a comprehensive way, I wouldn't want to dictate what helpers or patterns are defined for the implementation of i18n here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed 👍 Carry on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've kinda slowed down on #125 while these changes have been on the horizon, so that it doesn't get in your way while it's still half-baked. 😼
This looks awesome and has my 👍 to go. I went ahead and merged it into the In its current state, I say lets 🚢 this bad boy. I've got a Medium post good to go and the branch looks good with this functionality. Great work all around, everyone. Happy to see this go live (soon)! 👏 |
Sounds good. I'll leave this here for you to work in when/how ever you see fit. Fun project, best of luck! |
We're live! @mwerner you've got a mention in the blog post for this feature -- will ping you when it's up :) |
Hey team,
I got a significant portion of custom attributes (#92) written, but wanted to check in and see if this is in the direction you had in mind before continuing to finish the work and write specs. Let me know if this is something you could use. Thanks
An
AttributeCategory
has manyAttributeFields
. When one of the fields is provided a value, it saves the entity as a polymorphic association on theattributes
table. The bulk of the remaining work is improving the UI to actually create attribute categories, since they're a little different than your existingcontent
style models. There will also need to be a good amount of work around providing a correct value sincecontent.send(attribute)
wouldn't work with this pattern.Pardon a few spots where there are things like literals in the conditional, this isn't a finished PR, just a PoC.