Skip to content

A Demo app using Marty, Mcfly, Delorean, Netzke, and extjs.

Notifications You must be signed in to change notification settings

Solnse/marty_demo

Repository files navigation

Adding Marty to a new project.

add to Gemfile:

gem 'marty', git: "https://github.com/arman000/marty.git"

Marty currently requires netzke for the presentation layer, and since netzke requires extjs, we’re going to need to integrate it.

Install extjs somewhere on the machine and create a symbolic link to it as public/extjs

example: {PROJECT_ROOT}/public $ ln -s ~/repos/extjs-version extjs

Netzke also uses the FamFamFam Silk icon set, so you can copy them into public/images/icons folder. (or symlink)

Bring in the Marty migrations:

$ rake marty:install:migrations

Run the migrations:

$ rake db:migrate

Note: wait to run marty:seed until we set our marty-specific configs in our application.

Referencing and utilizing Marty components is namespaced so our application should also be namespaced which helps to keep code organized and clean. This means that components, models, views, and controllers should be in a subdirectory structure named the same as the application.

Create the directories for this purpose. If your app name is "example_app", create the following directories:

app/components/
app/components/example_app/
app/controllers/example_app/
app/models/example_app/
app/views/layouts/example_app/
app/lib/example_app/
app/db/example_app/

redirect application_controller to use our namespaced controller which inherits from marty.

app/controllers/application_controller.rb: replace everything with the following 2 lines:

	require ‘example_app/application_controller’
	ApplicationController = ExampleApp::ApplicationController

create application controller file:

app/controllers/example_app/application_controller.rb:

	class ExampleApp::ApplicationController < Marty::ApplicationController
		protect_from_forgery
		layout "example_app/application"
	end

Configure routes to mount the Marty Engine in the application and include netzke routes.

app/config/routes.rb:

    Rails.application.routes.draw do
        
        netzke
        mount Marty::Engine => "/example_app"
        get 'components/:component' => 'example_app/components#index', as: "components"
        get 'marty/components/:component' =>
      	        'marty/components#index', as: "marty/components"
        root 'example_app/components#home'
        
    end

Require marty in a main application file that will always get loaded.

lib/example_app.rb

	require ‘marty’

Change javascript includes to point to the javascript files we will be using, via netzke.

modify app/views/layouts/application.html.erb

**change:** <%= javascript_include_tag %> **to:** <%= netzke_init %>

Add marty config lines to app/config/application.rb in the class Application < Rails::Application block:

    # always load files from our lib directory.
    config.autoload_paths += %W(#{config.root}/lib)
    config.session_store :cookie_store, :key => '_example_app_session'

    # if using ldap, create the yml file for the variables below.
    ldap_yml = YAML.load_file("#{config.root}/config/ldap.yml")["ldap"]

    # marty requirements
    config.marty = ActiveSupport::OrderedOptions.new
    config.marty.roles = [:viewer,:admin,:dev,:user_manager]
    config.marty.class_list = []
    config.marty.auth_source = ‘local'
    config.marty.system_account = ‘marty’
    config.marty.local_password = 'marty'
    config.marty.autologin = 1

    # for ldap authentication
    config.marty.ldap = ActiveSupport::OrderedOptions.new
    config.marty.ldap.host      = ldap_yml["host"]
    config.marty.ldap.port      = ldap_yml["port"]
    config.marty.ldap.base_dn   = ldap_yml["base_dn"]
    config.marty.ldap.login     = ldap_yml["login"]
    config.marty.ldap.domain    = ldap_yml["domain"]

Create the ldap.yml file for the network variables.

app/config/ldap.yml

See app/config/ldap.yml.example

If you wish to use ldap authentication:

**change:** config.marty.auth_source = ‘ldap’

add your first marty user in your application db/seeds.rb:

		login = ‘ldap_username’ # your windows login name
		firstname = ‘FirstName’
		lastname = ‘LastName’
		if !Marty::User.find_by_login(login)
		user = Marty::User.new
		user.login = login
		user.firstname = firstname
		user.lastname = lastname
		user.active = true
		user.save!

		# this will give your user all roles listed in config.marty.roles listed above.
		Marty::Role.all.map { |role|
			ur = Marty::UserRole.new
			ur.user = user
			ur.role = role
			ur.save!
		}

We can now run the seeds:

$ rake marty:seed
$ rake db:seed  # if you created a Marty::User to populate in your db/seeds.rb file.

Note: If you are using ‘local’ auth_source, you can log into the application for the first time as the default user ‘marty’ with the password ‘marty’ (as set in the config above), and create new users as desired. You will notice that there is no password field in the Add User form. If using local authentication, a user’s password will be the same as their login name. Probably only useful for testing situations where you don’t want to hit the ldap server, but could potentially be used as a hook into other authentication services.

Now we need to create our controller for our application components.

app/controllers/example_app/components_controller.rb:

    require 'marty/permissions'
    require 'netzke/basepack/grid'
    require 'netzke/basepack/fields'
    require 'example_app/auth_app'

    class ExampleApp::ComponentsController < Marty::ComponentsController
    	def home
        	render inline: "<%= netzke :'auth_app' %>", layout: true
     	end
    end

Notice the last require we do for the application specific auth_app. We can use Marty’s built in auth_app, but we need to create our class to inherit from it in order to pass the namespaced class name.

create the auth_app:

app/components/example_app/auth_app.rb:

	require 'example_app'
    require 'marty/main_auth_app'
    require 'marty/permissions'
    class ExampleApp::AuthApp < Marty::MainAuthApp
    end
    AuthApp = ExampleApp::AuthApp

Now when we start up the server and go to local host, you will be presented with the basic application to login.

Making the Menus Work

To give your application configurability without the need of editing the source code directly, we’ll create a config view.

Before adding any new models to our project, we need to tell Marty about the namespace that we’ve created. We can do this by prefixing all our application-specific tables with an application table prefix.

Create 2 new files that will help define our models.

lib/example_app/migrations.rb

require 'marty/migrations'
module ExampleApp::Migrations
	include Marty::Migrations
	def tb_prefix
	  "example_app_"
	end
end

# some SQL commands to bypass McFly versioning (check your db docs for what you might need.) Useful for fixing records when you don’t want the change versioned.

def disable_triggers(table_name, &block)
  	begin
  	    execute("ALTER TABLE #{table_name} DISABLE TRIGGER USER;")
  	    block.call
  	ensure
    	execute("ALTER TABLE #{table_name} ENABLE TRIGGER USER;")
  	end
  end

def grant_view_permissions(permission, schema, view_name, role)
  	execute("GRANT #{permission} ON #{schema}.#{view_name} TO #{role};")
  end
end

app/models/example_app/base.rb

class ExampleApp::Base < ActiveRecord::Base
    self.table_name_prefix = "example_app_"
    self.abstract_class = true
end

Add the migrations file to our main application require file:

lib/example_app.rb

	
	require ‘example_app/migrations’

This matches Marty’s table naming convention and will help to keep the schema understandable. When creating new migrations, you should include ExampleApp::Migrations in the migration file before running it. If you are adding foreign keys, use the Marty method: add_fk to properly handle the namespaced tables.

Create the Config View

rails g migration create_example_app_configs key:string value:string

Require both fields and add the unique index:

db/migrate/{timestamp}_create_example_app_configs.rb:

class CreateExampleAppConfigs < ActiveRecord::Migration
    def change
        create_table :example_app_configs do |t|
        t.string :key, null: false
        t.string :value, null: false
    end
    add_index :example_app_configs, :key, unique: true
end

Next define the config model class:

app/models/example_app/config.rb:

class ExampleApp::Config < ExampleApp::Base
    validates_presence_of :key, :value
    validates_uniqueness_of :key
    delorean_fn :lookup, sig: 1 do
        |key|
        self[key]
    end

    def self.[]=(key, value)
        entry = find_by_key(key)
        if !entry
            entry = self.new
            entry.key = key
        end
    	entry.value = value.to_json
        entry.save!
        value
    end

    def self.[](key)
        entry = find_by_key(key)
        entry and entry.get_value
    end

    def self.del(key)
        entry = find_by_key(key)
        if entry
            result = entry.get_value
            entry.destroy
            result
        end
    end
end

Since Netzke will handle the view for us, we don’t need to create one. However, we should create a menu item on the main grid panel to get us there.

Open our main auth_app component and add the config_view to the system menu.

app/components/example_app/auth_app.rb:

class ExampleApp::AuthApp < Marty::MainAuthApp
    def system_menu
        res = super
        super[:menu] += [:config_view]
        res
    end

    # Then we need to create the action handler for netzke.
    action :config_view do |a|
        a.text     = ‘config’
        a.tooltip  = 'Manage system configuration'
        a.handler  = :netzke_load_component_by_action
        a.icon     = :cog
        a.disabled = !self.class.has_admin_perm?
    end
    component :config_view
end

That means we need to create the config view component too:

app/components/example_app/config_view.rb:

require 'marty/panel'
class ExampleApp::ConfigView < Marty::Grid
    has_marty_permissions \
    create: :admin,
    read: :admin,
    update: :admin,
    delete: :admin

    def configure(c)
        super
        c.title   = "Config"
        c.model   = "ExampleApp::Config"
        c.columns = [:key, :value]
        c.blank_text = 'xxx'
        c.enable_extended_search = false
        c.data_store.sorters     = {property: :key, direction: 'ASC'}
    end

    column :key do |c|
        c.flex = 1
    end

    column :value do |c|
        c.flex = 3
    end
end
ConfigView = ExampleApp::ConfigView

To get the Postings menu working, we need to create a monkey patch to let Marty know how to map the posting type permissions.

create monkey patch

lib/example_app/monkey.rb

require ‘marty/new_posting_form’
Marty::NewPostingForm.class_eval do
    has_marty_permissions BASE: :dev
end

About

A Demo app using Marty, Mcfly, Delorean, Netzke, and extjs.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published