Call to Subroutine from Catalyst Controller - perl

I am working on catalyst to design a front end for a database. I am new to perl and catalyst. I am stuck with one error in the controller.
I want to fetch gene names from one table and pass each gene name to a subroutine gene_name(call a subroutine gene_name) which will perform certain function. I some how fetched the column with gene names but they are in the form of Hash reference to other table. My call to gene_name is not working.
Any idea how to pass the values to the subroutine rather than reference?
My code is as follows:
my #gene_list = $c->model('Gene::GeneTable')->search({
},{
column =>[qw/symbol/],
}
);
foreach my $gene (#gene_list){
push #gene_aliases, &gene_name($gene);
}
The error I am getting after executing the code is as follows:
DBIx::Class::ResultSet::find(): Can't bind a reference (MyApp::Model::Gene::GeneTable=HASH(0x7ff6d88b7c58))
UPDATED
My gene_name() subroutine is in another module which I have included in the controller. Now I have changed the for loop(in controller) as following and currently it is passing gene name to gene_name() to fetch aliases(But query remains the same):
foreach my $gene (#gene_list){
push #gene_aliases, &gene_name($gene-> symbol);
}
I am accessing the #gene_aliases in my view file as follows:
[% FOREACH g in gene_aliases -%]
[% g %]
[% END -%]
The above code is fetching hash references instead of names in the page. I am not able to display the gene names on web page.If I give [% g.symbol %] in for loop then the page would be empty with no error message.Hope this would be sufficient information for answering my question. If not I would elaborate on it.
My SQL query is as follows:
Select Symbol from GeneTable;
Thanks in advance
UPDATED2
As I am not a full time programmer, I am asking these questions on the blog. Kindly help me resolve my issues. If in case I have search form which takes gene name from user and this gene name has to be passed to the gene_name() subroutine, how do I pass this (to the controller and how to call the gene_name()). Kindly help me in resolving this issue.
My form in view.tt is as follows:
<form method="post" action "[% c.uri_for('/gene')%]">
<input type="text" name="search_alias">
<input type="submit" name="alias_search" value="Search">
</form>
All my aliases are in the other table called Alias, which is been used in gene_name() subroutine.

Either the gene_name() function needs to expect a GeneTable object being passed to it, or you would call it like this: gene_name($gene->symbol).
Having said that, the Controller does not look like the right place for this, based on what limited information you've provided.
It would make a lot more sense to have gene_name as a method of Gene::GeneTable itself, ie:
package GeneTable;
...
sub gene_name {
my $self = shift;
my $gene_name = ... # do something with $self->symbol
$gene_name
}
...
So that the ->gene_name method is available to any GeneTable object in any context.
UPDATE following OP's initial two comments
It sounds like gene_name() (which possibly should be called gene_aliases()) is a method of a Gene object. Putting such a conversion into a Controller does not adhere to good MVC philosophy.
Presumably you have model code somewhere - MyApp/Model/Gene/ most likely - and this sub should exist inside Gene/GeneTable.pm. Then you could use it thus:
[%- FOREACH g IN gene_list -%]
[% g.symbol %]<br/><ul>
[%- FOREACH gn IN g.gene_name -%]
<li>[% gn %]</li>
[%- END -%]
</ul>
[%- END -%]
in your template, and anywhere else you have a GeneTable object or collection thereof.
UPDATE #2 Following updated question
DBIx:Class will return an array of objects when called in list context as you do. Perhaps you need to add some Data::Dumper->Dumper() calls to get a handle on what each step is returning to you.
I suggest you add the following line immediately after your call to ->search():
$c->log->debug("gene_list contains: ", Data::Dumper->Dumper(\#gene_list));
...and possibly the equivalent debug for #gene_aliases after you've populated that.
That might give you a clearer picture of what you're getting back from your search, but I'd hazard a guess you're getting Gene::GeneTable objects.

Related

How to convert txt file to html using perl

I have run some scripts to generate storage capacity report and configuration settings report using perl. I would like send this report to my mail id in html using perl.
Please note that I am new to perl programming.
Your question is very vague, so it's hard to be of much help. This might point you in the right direction though.
You basically have three tasks here.
Parse your report into data structures.
Use your data structures to generate an HTML document.
Send the HTML document by email.
I can't really help with step 1 as I know nothing about your report. If you have your file in CSV format, then Text:CSV will be useful to you. It's worth pointing out that if you're generating this report, then you could generate it in a format that is easier to parse - JSON, for example.
For step 2, I'd recommend a templating engine. I'd use the Template Toolkit, but other options are available. The idea is that you create a template file that contains all of your HTML with "tags" where you want your variable data to go. On a simple level it might look something like this:
<html>
<head><title>Some Title</title></head>
<body>
<h1>Some Title</h1>
<p>Blah...</p>
<table>
[% FOREACH row IN data -%]
<tr><td>[% row.value %]</td><td>[% row.another_value %]</td></tr>
[% END -%]
<table>
</body>
</html>
Assuming that's in a file called email.tt and you have your data in an array of hashes called #data, then you'd process the template like this:
use Template;
#data = ({
value => 'something',
another_value => 'something else',
}, {
value => 'something',
another_value => 'something else',
});
my $tt = Template->new;
$tt->process('email.tt', { data => \#data }, \$email_body)
or die $tt->error;
That will give you your expanded HTML in $email_body. And that brings us to step 3.
I recommend Email::Stuffer for sending email.
use Email::Stuffer;
Email::Stuffer->from ('you#example.com')
->to ('someone_else#example.com')
->html_body($email_body)
->send;

Perl - When <%method PREPARE> gets called

I am new to Perl Mason.
I came across this with the suggestion that service calls should be put inside PREPARE block. But when I placed my service calls inside it, seems like the code inside it is never getting executed itself.
<%method PREPARE>
Kindly suggest what is the above block for and its usage.
From the Mason Manual:
The base component class, Mason::Component, has but a few built-in
methods: handle, render, wrap, main, m, and cmeta.
The main method contains the mix of HTML and Perl in the main part of
the component.
You can add other methods that output HTML via the section;
these methods automatically have access to $self and $m.
<%method leftcol>
<table><tr>
<td><% $foo %></td>
...
</tr></table>
</%method>
...
<% # call leftcol method and insert HTML here %>
<% $.leftcol %>
Which means you are declaring a method named PREPARE without any argument lists by <%method PREPARE> and after writing the method body you will end it using </%method>.
And, later somewhere you will call it using <% $.PREPARE %>.For more info refer the Mason Manual.

How can I pull data in a controller and form for one model that is in a different model with out a foreign key relationship?

I am new to rails and haven't really done to much with data outside of the model.
I have a form that references a table controller for files. I want to add an dropdown that will display a list of projects from a project table for the user to assign a the file to a project if they want too. Assigning a project is not a requirement. The file can be unassigned to a project. I do have a project_id column in the file table for those projects assigned but it is allowed to be null and I did not build a relationship because I need to have cases where there are none.
Can someone please tell me how to do this?
When they evaluate the file, the screen posts back with a save or update button depending if it has already been saved in the database.
At the same time as the save and update pop up on the right I want to display a list box of the projects with an assign project button. If new just a list, if update either just a list because not assigned or display the selected value in the list if already assigned, while allowing them to change it from the list if desired.
In the file controller method that posts back to the UI I have this code:
#file_alias_filedata = FileAliasFiledata.all
#projects = Project.all
for update
#projects = Project.find(params[:id])
In the form I have this code:
<p> <label> Select Project to Assign:</label> <br />
<%= select_tag 'projects', (#projects.present? ? options_for_select(#projects, #selected_project) : []) %> </p>
The form runs but I get this in the dropdown box:
#<Project:0x))7ff531ab4518>
Can someone please help me figure out how to accomplish my task and why I see the strange box value?
What am I doing wrong?
Thank you for your help!
Assigning a project is not a requirement. The file can be unassigned
to a project. I do have a project_id column in the file table for
those projects assigned but it is allowed to be null
From the docs:
belongs_to(name, scope = nil, options = {}) public
Specifies a
one-to-one association with another class. This method should only be
used if this class contains the foreign key. If the other class
contains the foreign key, then you should use has_one instead. See
also ActiveRecord::Associations::ClassMethods’s overview on when to
use has_one and when to use belongs_to.
Methods will be added for retrieval and query for a single associated
object, for which this object holds an id:
association(force_reload = false)
Returns the associated object. nil is returned if none is found.
Likewise,
has_many(name, scope = nil, options = {}, &extension) public
Specifies
a one-to-many association. The following methods for retrieval and
query of collections of associated objects will be added:
collection(force_reload = false) Returns an array of all the
associated objects. An empty array is returned if none are found.
But belongs_to() and has_many() are supposed to make things more convenient for you. You certainly do not have to use them.
Next,
and why I see the strange box value? What am I doing wrong?
You see the strange value for the same reason the following two loops display different things:
class Dog
attr_reader :name
def initialize(name)
#name = name
end
end
#dogs = [
Dog.new("Sam"),
Dog.new("Betty"),
Dog.new("Pete"),
]
#dogs.each {|dog| puts dog}
#dog_names = #dogs.map {|dog| dog.name }
#dog_names.each {|dog_name| puts dog_name}
--output:--
#<Dog:0x0000010099a308>
#<Dog:0x0000010099a2b8>
#<Dog:0x0000010099a268>
Sam
Betty
Pete
You will see the same result if you do something like the following in a view:
<div>
<%= select_tag "dog", options_for_select(#dogs) %>
</div>
<div>
<%= select_tag "dog_name", options_for_select(#dog_names) %>
</div>
If you read the docs here:
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select
...you will see several examples, which should make it clear that options_for_select() takes an argument that is:
An array of Strings.
A Hash where both the keys and values are Strings.
An enumerable that iterates over some Strings.
etc.
Do you see a pattern? It's Strings! options_for_select() needs an argument that consists of Strings. If the argument is not a collection of Strings, e.g. an array of project objects, then options_for_select() tries to convert the objects to strings by calling to_s() on the objects. And the default to_s() method is Object#to_s() which is inherited by all objects and produces a string containing the class name and the object_id.
I am also new to rails, but I think you can try using the options_from_collection_for_select method.
<%= select_tag :search_state, options_from_collection_for_select(State.find(:all, :select => :name), :name, :name) %>
Hope this help. Cause it certainly helped me.

Template Toolkit, test for last iteration in a nested loop

I'm using template toolkit to form a simple JSON response (see the code below).
I need to put a comma after all elements of the response except the last.
I believe I need to make use of TTs iterator, however I'm not getting it right.
With this code, a comma is still printed on the end of the last element.
The problem lies with the section that contains
[% UNLESS outer.last && loop.last %],[% END %]
this should add a comma unless the outer and inner loops are on their last iteration.
Any help on what I'm getting wrong greatly appreciated.
{ "success": true, "filesdata": [
[%~ USE outer = iterator(objects); FOREACH object IN outer;
FOREACH rep IN object.reps;
IF rep.rep == reptype %]
{ "id":"[% object.id | xml %]", "url":"[% rep.src | xml %]", "story":"[% object.story | xml %]" }[% UNLESS outer.last && loop.last %],[% END %]
[%~ END;
END;
END ~%]
] }
This works for me:
[% IF loop.last %]}[% ELSE %]},[% END %]
Have you tried using the join vmethod? You can create a list and join it with a comma:
[% items.join(', ') %]
Having said that, you may also want to look at Template::Plugin::SimpleJson. You could create a hash and then pass it to this plugin. However you do decide to do it, you probably don't want to worry about quoting your JSON in the actual template file and using something like this could save you some heartache down the line.
There's also the option of creating the JSON outside of the template itself, but that's outside the scope of your question.

How can I override WRAPPER in a Template Toolkit template file?

Is there a way to disabling a WRAPPER that was set in new(\%config), through either the template, or a temporary override with parse()? I want to have a single default WRAPPER (that I'll use for 99.9% of my templates), but exclude a few.
I'm doing this all through Catalyst::View::TT just like the example in the configuration synopsis, except I don't want the WRAPPER to apply to all of my templates.
Edit the wrapper, to include a conditional like:
[% IF no_wrapper OR template.no_wrapper %] [% content %] [% ELSE %]
top;
[% content %]
bottom;
[% END %]
This allows me to disable the wrapper either (1) inside of template, or (2) from the stash.
[%- META no_wrapper = 1 -%]
$c->stash->{no_wrapper} = 1
META var ...; is a directive that makes var accessible through the template hash as template.var
source: http://wiki.catalystframework.org/wiki/gettingstarted/howtos/template_wrappers
Define exceptions in site/wrapper itself, and btw there are exceptions defined there already.
[% IF template.name.match('\.(css|js|txt)');
debug("Passing page through as text: $template.name");
content;
ELSE;
debug("Applying HTML page layout wrappers to $template.name\n");
content WRAPPER site/html + site/layout;
END;
-%]
I stumbled into the same problem, and created a more generalized solution that allows for dynamic switching of layouts, or to have no layout at all. See here:
More than one layout/wrapper with Dancer and Template::Toolkit