-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
[Discussion] Rewrite Comment Editor with React #9175
Comments
Lots of errors in CI for the draft PR #9176: The errors refer to |
This is coming along nicely. I have a list component that is able to iterate over an array of As you can see, the rendering is very weird with
|
<% if !@preview %> | |
<%= render partial: "notes/responses" %> | |
<% if @react %> | |
<% comments = @node.comments_viewable_by(current_user).includes([:replied_comments, :node]).order('timestamp ASC').to_a %> | |
<%# run rails methods on comments %> | |
<%# can't access rails methods within %> | |
<% comments.collect! do |comment| %> | |
<% comment_body = comment.render_body %> | |
<% comment_text = raw insert_extras(filtered_comment_body(comment_body)) %> | |
<% comment = comment.as_json %> | |
<% comment.merge({ "commentText" => comment_text }) %> | |
<% end %> | |
<%= react_component("CommentsContainer", { | |
comments: comments, | |
commentsHeaderText: translation('notes._comments.comments') | |
}) %> | |
<% else %> | |
<div id="legacy-editor-container"><%= render partial: "notes/comments" %></div> | |
<% end %> | |
<% end %> | |
</div> |
(Don't worry, I will move this bulky block into application_helper.js
when I'm done.)
This is kind of annoying to write this code, but it helps to anticipate the kind of state
the views must have.
Server-Side Rendering
I don't know much about this aspect of React, but rails-react
also has the option to render components server-side within the controller. See here and here. This would improve speed and performance a lot!
|
<div class="navbar-text float-left"> | |
<% if comment.author %> | |
<% if comment.author && comment.author.photo_file_name %> | |
<img alt="Comment Author Profile Picture" style="width:32px;margin-right:6px;" class="rounded-circle" src="<%= comment.author.photo_path(:thumb) %>" /> | |
<% else %> | |
<div style="vertical-align:middle;display:inline-block;height:32px;width:32px;margin-right:6px;background:#ccc;" class="rounded-circle"></div> | |
<% end %> | |
<% if comment.author.name != "" %> | |
<a href="/profile/<%= comment.author.name %>"><%= comment.author.name %></a> | |
<% else %> | |
<%= comment.name %> | |
<% end %> | |
<% end %> |
The problem is that the React state of comment
looks like this in my app:
{
"comments": [
{
"comment": {
"cid":2,
"pid":0,
"nid":46,
"uid":1,
"subject":"",
"comment":"Woohoo, here's an awesome comment!",
"hostname":"",
"timestamp":1613426027,
"status":1,
"format":1,
"thread":"01/",
"name":null,
"mail":null,
"homepage":null,
"aid":0,
"comment_via":0,
"message_id":null,
"tweet_id":null,
"reply_to":null,
"flag":0},
"commentText":"\u003cp\u003eWoohoo, here's an awesome comment!\u003c/p\u003e\n"
}
],
"commentsHeaderText": "Comments"
}
In other words, there isn't any author
key present in the comment
object.
Here's where the notes/_comment
partial is rendered in the notes/_commentS
partial:
plots2/app/views/notes/_comments.html.erb
Lines 2 to 13 in ff75433
<div id="comments" class="col-lg-10 comments"> | |
<% comments = @node.comments_viewable_by(current_user) %> | |
<h3><span id="comment-count"><%= comments.size %></span> <%= translation('notes._comments.comments') %></h3> | |
<%= javascript_include_tag "editorToolbar" %> | |
<%= javascript_include_tag "comment" %> | |
<div style="margin-bottom: 50px;" id="comments-list"> | |
<% comments.includes([:replied_comments, :node]).order('timestamp ASC').each do |comment| %> | |
<% if comment.cid == @node.comments&.first&.cid %><a id="last" name="last"></a><% end %> | |
<% if comment.reply_to.nil? %> | |
<%= render :partial => "notes/comment", :locals => {:comment => comment} %> | |
<% end %> |
- comments is at first
comments = @node.comments_viewable_by(current_user)
- it's passed to the
notes/_comment
partial here:<%= render :partial => "notes/comment", :locals => {:comment => comment} %>
- somehow
comment.author
is accessible here:<% if comment.author %>
I'm not able to access comment.author
when doing the same things in React. What am I missing here? How is the author
property of the comment
node defined in Rails? Is it some kind of lookup between two database tables? And where is that defined exactly when comments
is first defined as comments = @node.comments_viewable_by(current_user)
in the notes/_comments
partial above?
OK, so i'm thinking on how to "pack" the association (which in this case is not a real relation but just a query for This packs up whatever you want into a Hash format, which can then have Keep in mind this is a little more convoluted because in Ruby unlike JS we can't just assign arbitrary methods or attributes to an existing object, which is why we make a new object. So you might do something like (i think this should work): {
author => comment.author
}.to_json Although there are probably other ways to do it too! I'd be careful to try to do this only for the JSON response you're handing back to React, as it does add complexity and cost to the query if used in other scenarios where this wasn't deemed necessary. Are you doing it in a new controller action? Hope this helps! |
@jywarren Thanks, yeah that is helpful! I think that will help once I definitively know what needs to be in the massive I thought of another small question. Take a look at these lines I posted above from the new React revision: plots2/app/views/notes/show.html.erb Lines 128 to 129 in ff75433
I noticed that I wasn't able to set As you can see, there's a big up-front cost to making the massive Just to reiterate, it's also possible to render all the components server-side, which would boost performance by a lot! |
Hmm, interesting, so what are you aiming to do with the line |
It's like this:
I'm sure there's a much simpler way to do this, probably the MapKnitter example where I just construct the JSON object from scratch. Also this will all eventually end up in the controller so as not to complicate the views too much. I just want to know what the best way to do this in Ruby is. I'm more used to JavaScript where you can willy-nilly add keys and values to objects, so this is a little new for me. |
Ok, do you want to permanently write to the record, so it's saved in the database, or just to the temporary copy in memory, and it's ok if the comment doesn't retain the change? |
The second! 😊 Definitely don't want to save anything to the database, I just want to package up everything that React needs in a JSON |
Yes then your code looks good! I had to do something similarly odd to achieve the same in the mapknitter code but there are multiple ways to do it and you're right that the hard part is getting around the inability t write arbitrary attributes in Ruby. |
And i don't know what the most legible or standard way of doing this is but since it looks a bit odd maybe we should leave a comment like "temporarily add in extra attribute to a copy of the record in memory" or something? |
Yeah, definitely going to make comments all over the place. After I make some decent progress, I'll move this all to the controller and just make a fresh Hash object to hold all the JSON. Similar to the MapKnitter example. I think that will be a lot easier to read. |
…ions; pass parameters instead of using data attributes #9175
* git rebase * take ?react=true parameter #9175 * create & display hello world component #9175 * delete HelloWorld component * run Rails methods on comments state object * create components for comments, comment forms, & comment container * create react props for comment editor #9175 * add author pic, username, time posted, border, reply link #9175 * add userCommentedText prop #9175 * run views methods on react props #9175 * create comment toolbar #9175 * return nodeAuthorID and currentUser #9175 * toggle reply form; attach User Context #9175 * flesh out comment form #9175 * create User Context #9175 * create textarea, publish, & preview buttons #9175 * bundle text props as elementText object #9175 * destructure props with ES6 #9175 * destructure props with ES6 #9175 * create handlers for form submission and textarea input #9175 * explanatory comments #9175 * make AJAX request on form submission #9175 * rewrite get_react_comments so it doesn't return nil values #9175 * fix undefined ID bug: change commentId to formId #9175 * add webpacker startup to github actions runs * add webpack-dev-server start to gitpod.yml * switch to 'public/lib' instead of 'node_modules' * Update .gitpod.yml * Update .gitpod.yml * delete get_comment_react_props method #9175 * move get_react_comments to comment_helper.rb #9175 * render JSON for React comment editors #9175 * create state for comments; insert freshly posted comments into state #9175 * handle reply submission #9175 * create CommentsHeader component #9175 * extract comment author slug into its own component; create edit comment form #9175 * extract CommentReplies into its own component #9175 * rename to CommentAuthorSlug #9175 * change Comment key * handle edit form toggle #9175 * appease eslint * extract CommentDisplay and CommentHeader into separate components #9175 * extract CommentDisplay into its own component #9175 * consolidate CommentAuthorSlug into new CommentHeader component #9175 * pass linter #9175 * move formId calculation to CommentsContainer #9175 * break out CommentsList into its own component #9175 * generate default textAreaValues for edit forms #9175 * reset edit form textAreaValue when canceling edit #9175 * move elementText instantiation to controller #9175 * add makeDeepCopy function; extract everything to helpers.js #9175 * flash notification on comment post #9175 * dangerouslySetInnerHTML to display comment text #9175 * create edit comment functionality #9175 * rename parameter to getting_replies for clarity #9175 * change submit button's data- attributes #9175 * nest nodeId and nodeAuthor inside node #9175 * create StaticPropsContext #9175 * create handleDeleteComment function #9175 * newline at end of file #9175 * move all static props to StaticPropsContext #9175 * move commentFormVisibility state into CommentsContainer; close forms on submission #9175 * Update .gitpod.yml * Update .gitpod.yml * add rails generate commands for webpack * bundle exec * add functionality for deleting comments #9175 * remove webpack-dev-server line * remove webpacker-dev-server * add mysql env vars * added rails env * Update tests.yml * added snake_case, changed hash syntax to pass codeclimate #9175 * syntax tweaks to pass codeclimate #9175 * create readme file #9175 * undo reply nesting for comment state #9175 * remove is_reply parameter #9175 * set reply & edit isFormVisible, textAreaValue for new comments #9175 * add comments #9175 * stop passing down setTextAreaValues & replies as props #9175 * create CommentReplies in CommentsList #9175 * wrap CommentsContainer in new App component #9175 * break out handleFormSubmit into commentCreate and commentUpdate functions; pass parameters instead of using data attributes #9175 * upgrade node to v12 from v8 #9175 * setup guest browsing #9175 * replace replyCommentForm with link to login for anonymous browsing #9175 * add separate routes for React comments #9175 * fixes for codeclimate #9175 * add rails generate commandds for React & webpacker #9175 * remove rails generate webpacker/React commands #9175 * add rails g commands for webpacker & React #9175 * remove rails generate commands #9175 * add rails g commands for webpacker & React #9175 * add rails g commands for webpacker & React to deploy-container #9175 * remove rails generate react & webpacker commands from redeploy-container #9175 * re-add the command to redeploy-container; switch the order of statements #9175 * change webpack to webpacker in Makefile 🤦 #9175 * added the CORRECT webpacker & React commands to Makefile #9175 Co-authored-by: Jeffrey Warren <jeff@unterbahn.com>
…ab#9176) * git rebase * take ?react=true parameter publiclab#9175 * create & display hello world component publiclab#9175 * delete HelloWorld component * run Rails methods on comments state object * create components for comments, comment forms, & comment container * create react props for comment editor publiclab#9175 * add author pic, username, time posted, border, reply link publiclab#9175 * add userCommentedText prop publiclab#9175 * run views methods on react props publiclab#9175 * create comment toolbar publiclab#9175 * return nodeAuthorID and currentUser publiclab#9175 * toggle reply form; attach User Context publiclab#9175 * flesh out comment form publiclab#9175 * create User Context publiclab#9175 * create textarea, publish, & preview buttons publiclab#9175 * bundle text props as elementText object publiclab#9175 * destructure props with ES6 publiclab#9175 * destructure props with ES6 publiclab#9175 * create handlers for form submission and textarea input publiclab#9175 * explanatory comments publiclab#9175 * make AJAX request on form submission publiclab#9175 * rewrite get_react_comments so it doesn't return nil values publiclab#9175 * fix undefined ID bug: change commentId to formId publiclab#9175 * add webpacker startup to github actions runs * add webpack-dev-server start to gitpod.yml * switch to 'public/lib' instead of 'node_modules' * Update .gitpod.yml * Update .gitpod.yml * delete get_comment_react_props method publiclab#9175 * move get_react_comments to comment_helper.rb publiclab#9175 * render JSON for React comment editors publiclab#9175 * create state for comments; insert freshly posted comments into state publiclab#9175 * handle reply submission publiclab#9175 * create CommentsHeader component publiclab#9175 * extract comment author slug into its own component; create edit comment form publiclab#9175 * extract CommentReplies into its own component publiclab#9175 * rename to CommentAuthorSlug publiclab#9175 * change Comment key * handle edit form toggle publiclab#9175 * appease eslint * extract CommentDisplay and CommentHeader into separate components publiclab#9175 * extract CommentDisplay into its own component publiclab#9175 * consolidate CommentAuthorSlug into new CommentHeader component publiclab#9175 * pass linter publiclab#9175 * move formId calculation to CommentsContainer publiclab#9175 * break out CommentsList into its own component publiclab#9175 * generate default textAreaValues for edit forms publiclab#9175 * reset edit form textAreaValue when canceling edit publiclab#9175 * move elementText instantiation to controller publiclab#9175 * add makeDeepCopy function; extract everything to helpers.js publiclab#9175 * flash notification on comment post publiclab#9175 * dangerouslySetInnerHTML to display comment text publiclab#9175 * create edit comment functionality publiclab#9175 * rename parameter to getting_replies for clarity publiclab#9175 * change submit button's data- attributes publiclab#9175 * nest nodeId and nodeAuthor inside node publiclab#9175 * create StaticPropsContext publiclab#9175 * create handleDeleteComment function publiclab#9175 * newline at end of file publiclab#9175 * move all static props to StaticPropsContext publiclab#9175 * move commentFormVisibility state into CommentsContainer; close forms on submission publiclab#9175 * Update .gitpod.yml * Update .gitpod.yml * add rails generate commands for webpack * bundle exec * add functionality for deleting comments publiclab#9175 * remove webpack-dev-server line * remove webpacker-dev-server * add mysql env vars * added rails env * Update tests.yml * added snake_case, changed hash syntax to pass codeclimate publiclab#9175 * syntax tweaks to pass codeclimate publiclab#9175 * create readme file publiclab#9175 * undo reply nesting for comment state publiclab#9175 * remove is_reply parameter publiclab#9175 * set reply & edit isFormVisible, textAreaValue for new comments publiclab#9175 * add comments publiclab#9175 * stop passing down setTextAreaValues & replies as props publiclab#9175 * create CommentReplies in CommentsList publiclab#9175 * wrap CommentsContainer in new App component publiclab#9175 * break out handleFormSubmit into commentCreate and commentUpdate functions; pass parameters instead of using data attributes publiclab#9175 * upgrade node to v12 from v8 publiclab#9175 * setup guest browsing publiclab#9175 * replace replyCommentForm with link to login for anonymous browsing publiclab#9175 * add separate routes for React comments publiclab#9175 * fixes for codeclimate publiclab#9175 * add rails generate commandds for React & webpacker publiclab#9175 * remove rails generate webpacker/React commands publiclab#9175 * add rails g commands for webpacker & React publiclab#9175 * remove rails generate commands publiclab#9175 * add rails g commands for webpacker & React publiclab#9175 * add rails g commands for webpacker & React to deploy-container publiclab#9175 * remove rails generate react & webpacker commands from redeploy-container publiclab#9175 * re-add the command to redeploy-container; switch the order of statements publiclab#9175 * change webpack to webpacker in Makefile 🤦 publiclab#9175 * added the CORRECT webpacker & React commands to Makefile publiclab#9175 Co-authored-by: Jeffrey Warren <jeff@unterbahn.com>
…ab#9176) * git rebase * take ?react=true parameter publiclab#9175 * create & display hello world component publiclab#9175 * delete HelloWorld component * run Rails methods on comments state object * create components for comments, comment forms, & comment container * create react props for comment editor publiclab#9175 * add author pic, username, time posted, border, reply link publiclab#9175 * add userCommentedText prop publiclab#9175 * run views methods on react props publiclab#9175 * create comment toolbar publiclab#9175 * return nodeAuthorID and currentUser publiclab#9175 * toggle reply form; attach User Context publiclab#9175 * flesh out comment form publiclab#9175 * create User Context publiclab#9175 * create textarea, publish, & preview buttons publiclab#9175 * bundle text props as elementText object publiclab#9175 * destructure props with ES6 publiclab#9175 * destructure props with ES6 publiclab#9175 * create handlers for form submission and textarea input publiclab#9175 * explanatory comments publiclab#9175 * make AJAX request on form submission publiclab#9175 * rewrite get_react_comments so it doesn't return nil values publiclab#9175 * fix undefined ID bug: change commentId to formId publiclab#9175 * add webpacker startup to github actions runs * add webpack-dev-server start to gitpod.yml * switch to 'public/lib' instead of 'node_modules' * Update .gitpod.yml * Update .gitpod.yml * delete get_comment_react_props method publiclab#9175 * move get_react_comments to comment_helper.rb publiclab#9175 * render JSON for React comment editors publiclab#9175 * create state for comments; insert freshly posted comments into state publiclab#9175 * handle reply submission publiclab#9175 * create CommentsHeader component publiclab#9175 * extract comment author slug into its own component; create edit comment form publiclab#9175 * extract CommentReplies into its own component publiclab#9175 * rename to CommentAuthorSlug publiclab#9175 * change Comment key * handle edit form toggle publiclab#9175 * appease eslint * extract CommentDisplay and CommentHeader into separate components publiclab#9175 * extract CommentDisplay into its own component publiclab#9175 * consolidate CommentAuthorSlug into new CommentHeader component publiclab#9175 * pass linter publiclab#9175 * move formId calculation to CommentsContainer publiclab#9175 * break out CommentsList into its own component publiclab#9175 * generate default textAreaValues for edit forms publiclab#9175 * reset edit form textAreaValue when canceling edit publiclab#9175 * move elementText instantiation to controller publiclab#9175 * add makeDeepCopy function; extract everything to helpers.js publiclab#9175 * flash notification on comment post publiclab#9175 * dangerouslySetInnerHTML to display comment text publiclab#9175 * create edit comment functionality publiclab#9175 * rename parameter to getting_replies for clarity publiclab#9175 * change submit button's data- attributes publiclab#9175 * nest nodeId and nodeAuthor inside node publiclab#9175 * create StaticPropsContext publiclab#9175 * create handleDeleteComment function publiclab#9175 * newline at end of file publiclab#9175 * move all static props to StaticPropsContext publiclab#9175 * move commentFormVisibility state into CommentsContainer; close forms on submission publiclab#9175 * Update .gitpod.yml * Update .gitpod.yml * add rails generate commands for webpack * bundle exec * add functionality for deleting comments publiclab#9175 * remove webpack-dev-server line * remove webpacker-dev-server * add mysql env vars * added rails env * Update tests.yml * added snake_case, changed hash syntax to pass codeclimate publiclab#9175 * syntax tweaks to pass codeclimate publiclab#9175 * create readme file publiclab#9175 * undo reply nesting for comment state publiclab#9175 * remove is_reply parameter publiclab#9175 * set reply & edit isFormVisible, textAreaValue for new comments publiclab#9175 * add comments publiclab#9175 * stop passing down setTextAreaValues & replies as props publiclab#9175 * create CommentReplies in CommentsList publiclab#9175 * wrap CommentsContainer in new App component publiclab#9175 * break out handleFormSubmit into commentCreate and commentUpdate functions; pass parameters instead of using data attributes publiclab#9175 * upgrade node to v12 from v8 publiclab#9175 * setup guest browsing publiclab#9175 * replace replyCommentForm with link to login for anonymous browsing publiclab#9175 * add separate routes for React comments publiclab#9175 * fixes for codeclimate publiclab#9175 * add rails generate commandds for React & webpacker publiclab#9175 * remove rails generate webpacker/React commands publiclab#9175 * add rails g commands for webpacker & React publiclab#9175 * remove rails generate commands publiclab#9175 * add rails g commands for webpacker & React publiclab#9175 * add rails g commands for webpacker & React to deploy-container publiclab#9175 * remove rails generate react & webpacker commands from redeploy-container publiclab#9175 * re-add the command to redeploy-container; switch the order of statements publiclab#9175 * change webpack to webpacker in Makefile 🤦 publiclab#9175 * added the CORRECT webpacker & React commands to Makefile publiclab#9175 Co-authored-by: Jeffrey Warren <jeff@unterbahn.com>
Hooray! The first part of the React rewrite of the Comment System was merged in #9176.
Currently, the React system can do CRUD of comments. React and webpacker were installed in this phase.
There's an issue open here for Phase 2, which will measure performance with system tests, and add further functionality like emoji reactions, comment preview, etc: #9365
Let's see how this wild experiment goes! I installed React & Webpack on a development branch, and I'm going to see if I can reproduce the Comment Editor using React.Doing all my work in Draft PR #9176 and in the branch atreact-comments
The purpose of this is to figure out:Does React offer any significant advantage in terms of state management? As we've seen, Comment Editor state can get kind of complicated. And is this advantage worth it, weighing the cost-benefit of adding a new framework to the stack?If this is a worthwhile project, what other parts of the site can be given this treatment?Also Done in PR #9176
initialProps
that don't change into a context providerActionController::Base.helpers.<helper>
to add view helpers to the controller<%= raw %>
) to encode comment text properlyCommentsContainer
helper functions for reduced complexityformToggleState
andtextAreaValue
when fresh comment is postedsetTextAreaValues
isn't passed down 5-7 componentsCommentReplies
inCommentsList
, to avoid passing down propsCommentsContainer
in newApp
componentformSubmit
andbuttonClick
functions (notevent.target.dataset
)currentUser
/comment/REACT/create/46
(This issue is part of the larger Comment Editor Overhaul Project with Outreachy. Refer to Planning Issue #9069 for more context)
The text was updated successfully, but these errors were encountered: