Data mapper not saving object - sinatra

require 'rubygems'
require 'sinatra'
require 'data_mapper'
require 'dm-paperclip'
require 'haml'
require 'fileutils'
require 'dm-migrations/adapters/dm-sqlite-adapter'
require 'data_mapper'
require 'dm-migrations'
APP_ROOT = File.expand_path(File.dirname(__FILE__))
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/macerdo.db")
class DevApp
include DataMapper::Resource
include Paperclip::Resource
property :id, Serial
property :name, String
property :appDescription, String
property :priceInDollars, String
property :priceInUGX, String
property :created_at, DateTime
property :file , FilePath
DataMapper.finalize.auto_upgrade!
end
The above is my code.I am working on a site using sinatra.I tried to save an object but it fails without any errors.I looked for help online but I did not get a solution. I will appreciate any help.
I wrote this while trying to save.
#resource = DevApp.create(:file=>params[:file],:name => params[:name], :priceInDollars => params[:priceInDollars], :priceInUGX => params[:priceInUGX], :appDescription => params[:appDescription], :created_at => DateTime.now )

Related

How to use Class:DBI with own constructors or OO-systems like Moo(se)?

When using Class::DBI in Perl, the insert() method from Class::DBI acts as a constructor returning an object. How can I use Class::DBI in combination with object attributes that are not part of any database tables?
For example: I would like to have my Music::Artist class to have a version attribute that is part of the resulting objects (so that I can use this object attribute in my overall application logic), but does not get written to the database?
Ultimately I would like to be able to combine the usage of Class::DBI with OO-systems like Moo(se).
Vanilla Class:DBI example code from metacpan:
package Music::DBI;
use base 'Class::DBI';
Music::DBI->connection('dbi:mysql:dbname', 'username', 'password');
package Music::Artist;
use base 'Music::DBI';
Music::Artist->table('artist');
Music::Artist->columns(All => qw/artistid name/);
#-- Meanwhile, in a nearby piece of code! --#
my $artist = Music::Artist->insert({ artistid => 1, name => 'U2' });
Pseude-code of what I would like to do:
package Music::Artist;
use base 'Music::DBI';
use Moo;
Music::DBI->connection('dbi:mysql:dbname', 'username', 'password');
Music::Artist->table('artist');
Music::Artist->columns(All => qw/artistid name/);
has name => ( is => 'rw' );
has version => ( is => 'rw' );
#-- Meanwhile, in a nearby piece of code! --#
my $artist = Music::Artist->new( name => 'U2', version => '0.1.0' );
$artist = Music::Artist->insert({ artistid => 1, name => $artist->name });
# ... do something with $artist->version ...
(Although this code could run, Class::DBI's insert() of cause overrides the object returned by Moo's new() in the first place.)
How to combine Class::DBI with own or third-party (Moo) constructors?
I read Class::DBIs documentation but did not find any information on how to override insert() as an approach to supply a combined constructor method. I also tried to find repositories on GitHub that make use of Class::DBI and own constructors or OO-systems in the same packages, but did not succeed either.

Which files are needed for an own finisher to work in the Typo3 form extension?

I want to make my own finisher but I don't have a clue what is needed.
I have
\Domain\Finishers\MyOwnFinisher.php // with the finisher class
Configuration\Form\Backend.yaml //which should tell my TYPO3 where to look for the finisher
Configuration\TypoScript\setup.typoscript //telling EXT:form where the Backend.yaml is
but still I get an exception:
"The finisher preset identified by “xxx” could not be found, or the implementationClassName was not specified."
Is there some file I forgot? Some configuration I must set?
Backend.yaml
prototypes:
standard:
finishersDefinition:
MyOwn:
implementationClassName: 'mastar\testprivateext\Classes\Domain\Finishers\MyOwnFinisher'
options:
table: tx_testprivateext_domain_model_YetAnotherTable
setup.typoscript
#import "EXT:testprivateext/Configuration/TypoScript/Setup/*.typoscript"
plugin.tx_form.settings.yamlConfigurations {
901 = EXT:testprivateext/Configuration/Form/Backend.yaml
}
MyOwnFinisher.php
<?php
declare(strict_types=1);
namespace mastar\testprivateext\Classes\Domain\Finishers;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
use TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher;
class MyOwnFinisher extends AbstractFinisher {
protected $defaultOptions = [
'table' => 'tx_testprivateext_domain_model_YetAnotherTable',
'pid' => '34',
'name' => '',
'unterzeile' => '',
'strasse' => '',
'hausnummer' => '',
'plz' => '',
'ort' => '',
'telefon' => '',
'fax' => '',
'web' => '',
];
protected $shortFinisherIdentifier = 'MyOwn';
protected $databaseConnection;
protected function executeInternal() {
/// Stuff get's done here
}
}
Thanks in advance!
You have some definition in the yaml file, I complete it as I never know if you missed it or left it out:
TYPO3:
CMS:
Form:
prototypes:
standard:
finishersDefinition:
MyOwn:
implementationClassName: 'mastar\testprivateext\Classes\Domain\Finishers\MyOwnFinisher'
options:
table: tx_testprivateext_domain_model_YetAnotherTable
Beside that I never see an obvious fault and guess that you know the documentation how to write an own finisher.
One issue when new classes are added can sometimes be solved by clearing the cache and dumping autoload.
Furthermore it might be helpful to check the logfile, not all problems are reported by the log inside the TYPO3 backend.
EDIT:
I just see this is wrong:
implementationClassName:
'mastar\testprivateext\Classes\Domain\Finishers\MyOwnFinisher'
and should be instead:
implementationClassName:
'mastar\testprivateext\Domain\Finishers\MyOwnFinisher'
So actually you've to separate paths and namespace, they are similar but not the same. Important might be the vendor and extensionName in the namespace too, I'd advise to read the extbase tutorial if you never understand namespaces well.

How do I create a Catalyst::Model::DBIC::Schema from a DBIC::Schema?

Total lack of documentation makes this difficult..
Essentially, I have
package MyApp::Schema;
sub new_schema {
__PACKAGE__->connect(...)
}
Then I have
package MyCatApp::Model::MyApp;
use Moose;
extends 'Catalyst::Model::DBIC::Schema';
## what here;
_PACKAGE__->make_immutable;
How do I make this work? If I have this in my config...
<Model::MyApp>
schema_class MyApp::Schema
traits Caching
user_defined_schema_accessor foo
</Model::MyApp>
I get the following error:
BEGIN failed--compilation aborted at MyCatapp.psgi line 4, line 1.
Error while loading MyCatapp.psgi: Couldn't instantiate component "Either ->config->{connect_info} must be defined for MyCatApp::Model::MyApp or MyApp::Schema must have connect info defined on it.
But adding sub connect_info {} in MyApp::Schema does not change anything. That error is generated on line 480 of this file.
That method seems to be looking at $schema_class->storage->connect_info which I believe is an method on an instantiated object, and not a function in the package. However, if I try to set
__PACKAGE__->config('schema_class', MyApp::Schema->new_schema)
I then get...
Error while loading : Couldn't instantiate component "MyCatApp::Model::MyApp", "Attribute (schema_class) does not pass the type constraint because: Validation failed for 'Catalyst::Model::DBIC::Schema::Types::SchemaClass' with value MyApp::Schema=HASH(0xb4a5ff0) at /usr/local/lib/perl/5.18.2/Moose/Exception.pm line 37
So, how do I go about doing this...
So.. I'm not sure this is right so I won't mark it as accepted but I was pretty damn close.. This line is dead on..
__PACKAGE__->config('schema_class', MyApp::Schema->new_schema)
And the code is in place for that to work, as per the link above on line 480 of Catalyst::Model::DBIC::Schema. However, the type is wrong..
The type of schema_class is SchemaClass. And, SchemaClass is defined here
subtype SchemaClass,
as LoadableClass,
where { $_->isa('DBIx::Class::Schema') };
Now, SchemaClass is a subtype of a MooseX::Types::LoadableClass which essentially just takes a package name and requires it..
The problem is LoadableClass doesn't take an instance of DBIC::Schema. Anyway.. I was just changed it too..
has schema_class => (
is => 'ro',
isa => 'Object',
required => 1
);
Now I can stuff an instantiated schema into schema_class and pass the conditional if($schema_class->storage && $schema_class->storage->connect_info).
I filed a bug on this here
You could instantiate the connection info in your MyApp::Schema by in it doing:
__PACKAGE__->connection(#your_connection_details);
This will set up a Storage on the class itself, not a schema object. This will then pass the Catalyst::Model::DBIC::Schema check and work successfully. I think this achieves what you're after without changing the underlying classes (though might depend on the details not included).
From the documentation you referenced, your MyCatApp::Model::MyApp would look like this:
__PACKAGE__->config(
schema_class => 'MyApp::Schema',
connect_info => {
dsn => 'dbi:Pg:dbname=mypgdb',
user => 'postgres',
password => '',
pg_enable_utf8 => 1,
on_connect_do => [
'some SQL statement',
'another SQL statement',
],
}
);
And in your controller, you would:
my $db = $c->model('MyApp');

How can I use a local (or per view) variable in Sinatra with Haml partials?

I have a Haml partial in Sinatra to handle all of my 'page open' items like meta tags.
I would love to have a variable for page_title in this partial and then set that variable per view.
Something like this in the partial:
%title #page_title
Then in the view, be allowed to do something like:
#page_title = "This is the page title, BOOM!"
I have read a lot of questions/posts, etc. but I don't know how to ask for the solution to what I am trying to do. I'm coming from Rails where our devs usually used content_for but they set all that up. I'm really trying to learn how this works. It seems like I have to define it and use :locals in some way but I haven't figured it out. Thank you in advance for any tips!
You pass variables into Sinatra haml partials like this:
page.haml
!!!
%html{:lang => 'eng'}
%body
= haml :'_header', :locals => {:title => "BOOM!"}
_header.haml
%head
%meta{:charset => 'utf-8'}
%title= locals[:title]
In the case of a page title I just do something like this in my layout btw:
layout.haml
%title= #title || 'hardcoded title default'
Then set the value of #title in routes (with a helper to keep it short).
But if your header is a partial then you can combine the two examples like:
layout.haml
!!!
%html{:lang => 'eng'}
%body
= haml :'_header', :locals => {:title => #title}
_header.haml
%head
%meta{:charset => 'utf-8'}
%title= locals[:title]
app.rb
helpers do
def title(str = nil)
# helper for formatting your title string
if str
str + ' | Site'
else
'Site'
end
end
end
get '/somepage/:thing' do
# declare it in a route
#title = title(params[:thing])
end

Using Moose, how do I set the value of a 'ro' Attribute Trait, in runtime?

I've got an Attribute Trait that I want to set on the basis of other class attributes. I realy want a default on an Attribute Trait that gets a copy of the class $self and not the meta for the attribute. I want to do something like this in my class:
after 'BUILD' => sub {
my $self = shift;
$self->meta->get_attribute('id')->column_name( $self->_unique_key_name );
};
But, I want to keep my attribute trait RO? Is this possible. I know the MOP allows one to set the value of a class-attribute, but I can't figure out how to set an attribute on the meta-attribute.
This sounds like a really odd design (why would a metaclass need an instance of a class it is describing?) -- but you can do this easily enough by using the metaclass of the metaclass (remember that Moose meta classes are bootstrapped using the MOP itself):
$self->meta->meta->get_attribute("foo")->default($some_value);
Also remember that defaults need to be wrapped in a coderef if they are references themselves: $some_value = sub { $instance };
Actually, this won't work - 'default' is read only. Rather than fiddling with the MOP at such a low level, I would urge you to reconsider your design - e.g. store your 'default' in another attribute, and writing a default sub that delegated to it:
package MyApp::Meta::Attribute::Trait::Foo;
# set at runtime, when we have an instance to store here
has _default_of_foo => (
is => 'rw', isa => 'Object',
);
has foo => (
is => 'ro', isa => 'Object',
lazy => 1,
default => sub { shift->_default_of_foo },
);