{"id":15152710,"url":"https://github.com/blocknotes/contents_core","last_synced_at":"2025-09-29T23:32:05.969Z","repository":{"id":62556199,"uuid":"96607122","full_name":"blocknotes/contents_core","owner":"blocknotes","description":"Simple structure to manage contents in a flexible way","archived":true,"fork":false,"pushed_at":"2018-07-02T19:47:50.000Z","size":125,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-15T00:17:25.539Z","etag":null,"topics":["cms","rails","rails5","ruby","ruby-on-rails"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blocknotes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-08T08:49:03.000Z","updated_at":"2023-06-19T08:58:22.000Z","dependencies_parsed_at":"2022-11-03T06:00:24.371Z","dependency_job_id":null,"html_url":"https://github.com/blocknotes/contents_core","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fcontents_core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fcontents_core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fcontents_core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Fcontents_core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blocknotes","download_url":"https://codeload.github.com/blocknotes/contents_core/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234673608,"owners_count":18869698,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms","rails","rails5","ruby","ruby-on-rails"],"created_at":"2024-09-26T16:21:36.288Z","updated_at":"2025-09-29T23:32:00.591Z","avatar_url":"https://github.com/blocknotes.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ContentsCore [![Gem Version](https://badge.fury.io/rb/contents_core.svg)](https://badge.fury.io/rb/contents_core) [![Build Status](https://travis-ci.org/blocknotes/contents_core.svg)](https://travis-ci.org/blocknotes/contents_core) [![Dependency Status](https://gemnasium.com/badges/github.com/blocknotes/contents_core.svg)](https://gemnasium.com/github.com/blocknotes/contents_core) [![Test Coverage](https://api.codeclimate.com/v1/badges/59196100a1ebb599b088/test_coverage)](https://codeclimate.com/github/blocknotes/contents_core/test_coverage)\n\nA Rails gem which offer a structure to manage contents in a flexible way: blocks with recursive nested blocks + items as \"leaves\"\n\n_Disclaimer: this component is in ALPHA, major changes could happen_\n\nGoals:\n- attach the contents structure to a model transparently\n- add fields to blocks without migrations\n- offer helpers to render blocks in views\n- cache-ready\n\n## Install\n\n- Add to the Gemfile:\n`gem 'contents_core'`\n- Copy migrations (Rails 5.x syntax, in Rails 4.x use `rake`):\n`rails contents_core:install:migrations`\n- Execute migrations\n- Add the concern *Blocks* to your model (ex. *Page*): `include ContentsCore::Blocks`\n- Optionally add the blocks to a view (ex. *page show*): `= render partial: 'contents_core/blocks', locals: { container: @page }`\n\n## Usage\n\n### Working with blocks/items\n\n- Basic operations (example parent model: *Page*):\n```ruby\npage = Page.first\npage.create_block :slider, name: 'a-slider', create_children: 3  # Create a silder with 3 slides\npage.current_blocks.map{ |block| block.name }  # current_blocks -\u003e all published ordered blocks and query cached\nblock = page.get_block 'a-slider'\nblock.tree  # list all items of a block\nblock.get 'slide-2.title'  # get value of 'title' field of sub block with name 'slide-2' (name automatically generated at creation)\nblock.set 'slide-2.title', 'A title'  # set field value\nblock.save\n```\n\n- Other operations:\n```ruby\nblock = ContentsCore::Block.last\nContentsCore.create_block_in_parent block, :text  # create a sub block in a block\nblock.create_item :item_string, name: 'a-field'\n```\n\n## Config\n\nEdit the conf file: `config/initializers/contents_core.rb`\n\n```ruby\nmodule ContentsCore\n  @@config = {\n    blocks: {\n      text: {\n        name: :text_only,       # used as reference / for translations\n        children: {             # children: sub blocks \u0026 items\n          title: :item_string,\n          content: :item_text\n        }\n      },\n      image: {\n        name: :image_only,\n        children: {\n          img: :item_file\n        }\n      },\n      slide: {\n        name: :a_slide,\n        child_only: true,       # used only as child of another block (slider)\n        children: {\n          img: :item_file,\n          link: :item_string,\n          title: :item_string\n        }\n      },\n      slider: {\n        name: :a_slider,\n        new_children: :slide,   # block type used when creating a new child with default params\n        children: {\n          slide: :slide\n        }\n      },\n    },\n    items: {\n      item_boolean: {},\n      item_datetime: {},\n      item_float: {},\n      item_hash: {},\n      item_file: {\n        input: :file_image\n      },\n      item_integer: {},\n      item_string: {},\n      item_text: {\n        input: :html\n      },\n    }\n  }\nend\n```\n\nCreate the new view blocks: `app/views/contents_core/_block_custom.html.slim`\n\n```slim\n- if block\n  .title = block.get( 'title' )\n  .text == block.get( 'content' )\n  .image = image_tag block.get( 'image' ).url( :thumb )\n```\n\n### Images\n\nTo add support for images add CarrierWave gem to your Gemfile and execute: `rails generate uploader Image` and update che config file *config/initializers/contents_core.rb* with:\n\n```rb\nmodule ContentsCore\n  ItemFile.class_eval do\n    mount_uploader :data_file, ImageUploader\n\n    def init\n      self.data_file = File.open( Rails.root.join( 'public', 'images', 'original', 'missing.jpg' ) )\n      self\n    end\n  end\nend\n```\n\nAnother way is to override the *ItemFile* model (*app/models/contents_core/item_file.rb*):\n\n```rb\nmodule ContentsCore\n  class ItemFile \u003c Item\n    mount_uploader :data_file, ImageUploader\n\n    alias_attribute :data, :data_file\n\n    def init\n      self.data_file = File.open( Rails.root.join( 'public', 'images', 'original', 'missing.jpg' ) )\n      self\n    end\n\n    def self.type_name\n      'file'\n    end\n  end\nend\n```\n\n## Customizations\n\nTo create a \"free form\" block just use: `Page.first.create_block :intro, name: 'IntroBlock', schema: { intro: :item_string, subtitle: :item_string }`\n\nThen create a *app/view/contents_core/_block_intro* view.\n\nTo list the blocks of a page manually (but *current_blocks* method is the preferred way): `Page.first.cc_blocks.pluck :name`\n\nTo add a new field to an existing block (ex. to first Page, on the first Block):\n\n```rb\nblock = Page.first.get_block 'text-1'\nblock.create_item( :item_string, name: 'new-field' ).set( 'A test...' ).save\n```\n\nThen add to the block view: `block.get( 'new-field' )`\n\nTo set a field value: `block.set( 'new-field', 'Some value' )`\n\n### ActiveAdmin\n\nIf you use ActiveAdmin as admin interface you can find a sample model configuration: [page](extra/active_admin_page.rb) plus a js [page](extra/active_admin.js)\n\n## Notes\n\n- Blocks enum: `ContentsCore::Block.enum`\n- Blocks types: `ContentsCore::Block.types`\n- Default blocks [here](config/initializers/contents_core.rb)\n\n### Structure\n\n- Including the Blocks concern to a model will add `has_many :cc_blocks` relationship (the list of blocks attached to a container) and some utility methods\n- Block: UI component, a group of items (ex. a text with a title, a slider, a 3 column text widget, etc.); built with a list of sub blocks (for nested components) and a list of items\n- Item: a single piece of information (ex. a string, a text, a boolean, an integer, a file, etc.) with a virtual method named *data*\n\n## Contributors\n\n- [Mattia Roccoberton](http://blocknot.es) - creator, maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Fcontents_core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblocknotes%2Fcontents_core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Fcontents_core/lists"}