Skip to content

Add ContentBlocks#3839

Merged
mrcasals merged 22 commits intomasterfrom
content-blocks
Jul 30, 2018
Merged

Add ContentBlocks#3839
mrcasals merged 22 commits intomasterfrom
content-blocks

Conversation

@mrcasals
Copy link
Copy Markdown
Contributor

@mrcasals mrcasals commented Jul 12, 2018

🎩 What? Why?

This PR adds the concept of "content blocks" to Decidim. As of now, content blocks are only used in the home page.

A content block is a sortable, configurable layout block registered by a Decidim module.

Differences with view hooks?

On a view hook you can only hook a partial. There's no possibility of manual configuration, and even though you can set a priority, hooked views in the same priority cannot get sorted.

Examples of content blocks usage
# Registering a content block with static hard-coded options
Decidim.content_blocks.register(:homepage, :highlighted_processes) do |content_block|
  content_block.option :count, :integer, default: 4, values: [4, 8, 12]
  content_block.cell "decidim/participatory_processes/homepage_processes_block"
end

# A content block where options are analysed on runtime
Decidim.content_blocks.register(:homepage, :global_stats) do |content_block|
  content_block.option :minimum_priority_level,
                    :integer
                    default: lambda { StatsRegistry::HIGH_PRIORITY }
                    values: lambda { [StatsRegistry::HIGH_PRIORITY, StatsRegistry::MEDIUM_PRIORITY] }
  content_block.cell "decidim/content_blocks/stats_block"
end

# A content block with images
Decidim.content_blocks.register(:homepage, :carousel) do |content_block|
  content_block.image :image_1
  content_block.image :image_2
  content_block.image :image_3
  content_block.cell "decidim/carousel_block"
end

📌 Related Issues

📋 Subtasks

  • Add CHANGELOG entry
  • Add a ContentBlockRegistry
  • Add the ContentBlock manifest object
  • Rename ContentBlock to ContentBlockManifest
  • Add images to content blocks
  • Add options to content blocks
  • Move homepage sections to cells
  • Move the different current sections to content blocks
  • Use registered content blocks on the homepage to ensure this works.
  • Add the ContentBlock model. Should have many attachments (images). DB columns:
    • organization_id
    • content_block_name
    • scope
    • options (JSONB field)
    • position
    • published_at
  • Create content blocks during the seed phase
  • Use published content blocks in the homepage
  • Add migration to create default content blocks for each organization
  • Create default content blocks on organization registration (modify the RegisterOrganization command in system)

In later PRs:

@mrcasals mrcasals self-assigned this Jul 12, 2018
@mrcasals mrcasals force-pushed the content-blocks branch 5 times, most recently from 2807add to a751655 Compare July 12, 2018 14:04
@josepjaume
Copy link
Copy Markdown
Contributor

@mrcasals nice approach 👍. We should definitely build this in a way that it doesn't become dramatic to generalize in the future. Maybe adding a scope when registering a content block might make the API more flexible?

Something like:

Decidim.content_blocks.register(:home_page, :global_stats) do
  # ...
end

Or even:

Decidim.content_blocks[:home_page].register(:global_stats) do
  # ...
end

@mrcasals
Copy link
Copy Markdown
Contributor Author

@josepjaume that's what I wanted feedback of. I think we don't have a use case right now where this could be useful except for the homepage, and abstracting and reusing the admin section is not that simple.

Still, I'd go with the first suggestion.

@josepjaume
Copy link
Copy Markdown
Contributor

Yeah, I definitely understand the reasons behind it. But using this API makes the use case more explicit from the reader's point of view, and also will potentially prevent us from having to modify this part of the code when we extend it.

@mrcasals mrcasals force-pushed the content-blocks branch 3 times, most recently from c361021 to c11a6cd Compare July 16, 2018 09:08
@mrcasals
Copy link
Copy Markdown
Contributor Author

@josepjaume done! I've modified the PR description and the code docs accordingly.

@mrcasals mrcasals force-pushed the content-blocks branch 9 times, most recently from 3fcb666 to c586f73 Compare July 17, 2018 10:53
@mrcasals mrcasals force-pushed the content-blocks branch 5 times, most recently from 19b7e66 to e9f8ce9 Compare July 25, 2018 13:32
@mrcasals
Copy link
Copy Markdown
Contributor Author

mrcasals commented Jul 27, 2018

Following @deivid-rodriguez's suggestion (#2476 (comment)), I'm gonna add a few things a send this PR for review.

This PR adds the backbones for ContentBlocks, and uses them in the homepage. I need to add a migration to create the default content blocks for existing organizations, and create the default content blocks on organization registration.

@mrcasals mrcasals changed the title [WIP] Add ContentBlocks Add ContentBlocks Jul 30, 2018
@ghost ghost added the status: WIP label Jul 30, 2018
render
end

delegate :current_organization, to: :controller
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe we can add this to Decidim::ViewModel?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I won't do it by now as it might affect other cells.

belongs_to :organization, foreign_key: :decidim_organization_id, class_name: "Decidim::Organization"

def manifest
Decidim.content_blocks.for(scope).find { |manifest| manifest.name.to_s == manifest_name }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we memoize this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

t.string :manifest_name, null: false, index: true
t.string :scope, null: false, index: true
t.jsonb :options
t.datetime :published_at
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add an index here (I guess we're only showing the published ones)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe we need a combined index with decidim_organization_id, can you try an run an explain on the query to see which is better?

# frozen_string_literal: true

module Decidim
class ContentBlockManifest

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done


<% if !translated_attribute(current_organization.description).blank? %>
<%= render partial: "decidim/pages/home/sub_hero" %>
<% Decidim::ContentBlock.where(organization: current_organization, scope: :homepage).where.not(published_at: nil).order(weight: :asc).each do |content_block| %>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe move all these conditions to a scope? (Also, related to the index comment for the database)

# content_block.cell "decidim/content_blocks/carousel_block"
# end
#
# You will probably want to register your content blocs in an initializer in
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

s/blocs/blocks

@mrcasals mrcasals merged commit a58eb46 into master Jul 30, 2018
@mrcasals mrcasals deleted the content-blocks branch July 30, 2018 09:56
@deivid-rodriguez
Copy link
Copy Markdown
Contributor

@deivid-rodriguez I know your comment wasn't targeting this PR, but still! What I dislike of my approach is that if I later find that I need to refactor some things, context gets a little lost. For this PR I'd rather use different PRs:

  • This one could be considered an internal refactor
  • A later PR will come with the admin side that allows adding/removing content blocks, and reordering them
  • Another PR will add the options to content blocks, and the admin layouts to handle that.

I see, you're right about refactorings losing content. Your approach for this feature looks good!

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.

4 participants