CFWheels: Map table to another database Database.tablename - coldfusion

I have a datasource called "cforms" which has access to two database
"cforms" and "cquizes"
I wish to create the following query:
select * from cquizes.tb_depts;
I have a model for table "tb_depts":
<cfcomponent extends="Model">
<cffunction name="init">
<cfset table("tb_depts")>
</cffunction>
</cfcomponent>
And my controller:
list = model("tb_depts").findAll(order="id");
When I run this controller/action. It gives me the following error:
[Macromedia][Oracle JDBC Driver][Oracle]ORA-00942: table or view does not exist
And it generates the following query:
SELECT * FROM tb_depts
I understand what the problem is because since "tb_depts" doesn't exist in database "cforms" it throws that not found error. However is there are way to tell the model that using the datasource "cforms" access database "cquizes". For example
cquizes.tb_depts
Its seems to use the database that matches the datasource name. Is there a way to work around this functionality.

If you need to get data from another database, There is an alternative way. For that you need to create a datasource for your second database cquizes. Then use that datasource name in the model file. This will override default datasource for that model.
For example, If you name your second datasource as cquizdatasource then in your model would be like
<cfcomponent extends="Model">
<cffunction name="init">
<cfset dataSource("cquizdatasource")>
<cfset table("tb_depts")>
</cffunction>
</cfcomponent>
Your query should work fine with the said scenario in the question. There are limitations to this, check out the link to know more.

Related

Coldfusion global user object

I am trying to set a coldfusion user object for each person as they log in. Similar to how rails has devise and I can call current_user.id or current_user.username from wherever I am in the site. I have a users table that stores roles and other user information. I want to query that and assign all of the fields to a sort of global user object. I can then use that for components, page display etc.
I am trying to figure out where and how to do this. I have tried initializing a component like this in onsessionstart, onrequeststart etc, but when I try to reference globalUser.id in a component for instance it hits a 500 error because globalUser is not defined.
<cfset globalUser = CreateObject( "component",
"controllers.user" ).globalUser(empidname= '#getauthuser()#') />
Any recommended ways to do this? Any plugins that provide functionality like this?
You want to use session variables.
<cffunction name="onSessionStart">
<cfset session.globalUser = CreateObject( "component",
"controllers.user" ).globalUser(empidname= '#getauthuser()#') />
...
</cffunction>
In order for sessions to be enabled, you have to alter application.cfc
component {
this.name = "AppName";
this.sessionManagement = true;

How to add attributes ColdFusion tags in bulk

I was curious if there is a way to force a ColdFusion tag to hold an attribute as default, such as the datasource in cfquery.
For example instead of writing
<cfquery datasource="mydatasource">
I can write
<cfquery>
and the system automatically knows that the datasource is "mydatasource".
Would be really cool if this was possible.
It is actually possible for datasource, but not for everything.
You may set a this.datasource="mydatasource" as the default datasource in your Application.cfc
https://wikidocs.adobe.com/wiki/display/coldfusionen/Application+variables
The practical answer to your question are the custom tags. You can extend the features of ColdFusion tags to match your needs.
Taking into example the cfquery tag and wrapping a custom tag around it. Provide all the default values you want for the parameters of the cfquery into the tag's attribute default.
So essentially your custom tag page would be something like:
flexiquery.cfm
<cfif THISTAG.ExecutionMode EQ 'end'>
<cfparam name="Attributes.datasource" default="someDSN">
<cfparam name="Attributes.cacheWithin" default="#CreateTimeSpan(0,6,0,0)#">
<cfparam name="Attributes.maxRows" default="25">
<cfparam name="Attributes.timeOut" default="600">
<!--- some logic you want to perform --->
<cfquery datasource="#Attributes.datasource#"
cacheWithin="#Attributes.cacheWithin#"
maxRow="#Attributes.maxRows#"
timeOut="#Attributes.timeOut#"
<cfoutput>#THISTAG.GeneratedContent#</cfoutput>
</cfquery>
<!--- Caller assignment and other processing --->
</cfif>
And now you can use it and re-use it across your project, the way you wanted and even overriding the value you want to be different:
<cf_flexiquery>
<!--- you query here --->
</cf_flexiquery>
or
<cf_flexiquery maxRows="100" timeOut="1200">
<!--- you query here --->
</cf_flexiquery>
It gives you a fair idea of how to go with it. I have extended the custom tags features to leverage the features of cfhttp, cfpdf, cffile etc.
This is only way you can adopt the flexibility you want with ColdFusion tags and it works perfectly.

Error with Coldfusion cftransaction tag

I'm working with ColdFusion 11 and am getting an error with cftransaction. I'm not sure what causing it.
I have two CFC's: abc.cfc and xyz.cfc. abc.cfc does not use the datasource attribute: as it is defined in the Application.cfc using this.datasource.
Here is the error:
Error! The root cause was that: java.sql.SQLException: Usernames and Passwords for all the database tags within the cftransaction tag must be the same. Datasource inventorymgt verification failed.. Entry rolled back
What I am doing is:
<cftransaction action="begin">
<cftry>
<cfscript>
f = structNew();
f.companyName = '#arguments.structform.companyname#';
f.address = '#arguments.structform.address#';
f.settingsID = arguments.structform.settingsID;
r = tblUpdate('settings',f);
sresult = 'Updated';
</cfscript>
<cfset str = "Cool! Settings has been " & sresult>
<cftransaction action="commit"/>
<cfcatch type="any">
<cftransaction action="rollback"/>
<cfset str = "Error! #cfcatch.Detail# #cfcatch.Message#. Entry rolled back">
</cfcatch>
</cftry>
</cftransaction>
And another CFC which is expecting the init function like the datasource, username,password is using the following query way to update it:
<cfquery name="q"
datasource="#variables.dbsource#"
username="#variables.dbuname#"
password="#variables.dbpword#">
I think the reason is explained in this post:
https://groups.google.com/forum/#!topic/cfwheels/AZTvxvhsapc
Within a cftransaction tag, every query has to use the same authentification. You cannot have one query use a datatasource and the other use a username and password within the same transaction.
I would agree with the author of the link. I always just define the datasource once in the cf-administrator, so I don't have to deal with username/password. Then you can initialize your cfc just by datasource.
I don't know what your function tblUpdate is actually doing, but might be that you use a different syntax than in the query you posted? Because, that's what your error code says:
Usernames and Passwords for all the database tags within the cftransaction tag must be the same.

cfwheels and object helpers

I've got a set of processes I frequently do to a model that I keep redoing in the controller, and I'm wondering if there is a way to implement it through a function in the model, so that I can just call the model function pass some parameters and get the right query.
I've got a linked list, and there's a bit of repetition that I want to avoid.
figured it out...
in model:
<cffunction name="getCustomResults" returntype="query">
<cfset all = findAll()>
<!--- do stuff --->
<cfreturn myQuery>
</cffunction>
getting the custom results
<cfset mySelection = model('myModel').getCustomResults()>
if there is a way to do implement it through a function in the model
Can you please tell what stops you from doing exactly this? Simply create CFC like /models/Foo.cfc where foo is name of your model and extend it with methods. Just don't forget to extend the Model.cfc. See this docs section. Inside the model you have this scope which holds all properties.

Is onApplicationStart is good Idea in ColdFusion?

I have to use a Variable(Query Resultset) in ColdFusion, which will get the results from Other Application DB, and stores in Coldfusion Application.
The main idea is that I need to call the other Application DB only at Server startup time and cache the results in local. And I need to read the variable in other pages in my Application. I won't overwrite that variable in any page.
On googling I found that 'onApplicationStart' is useful to assign the variables at Application Startup time.
Is using the onApplicationStart fine or is there any other way? We can assign a variable at startup time(one time).
If onApplicationStart is fine: how to use? Maybe any link where it is explained clearly is helpful.
Well, it depends. How often will this query data be updated? If it really is unchanging, then onApplicationStart() is a fine place to put it. However, if it will change every so often, you can just tell Coldfusion to cache the query for a certain period of time, then you don't need to mess with onApplicationStart(), but rather when you call the query it will return the cached result automatically (within your specified time period).
Regardless, I would write a custom function to retrieve the data. Then it will be trivial to call it from onApplicationStart() or elsewhere.
Startup.cfc: (Named whatever you like)
<!--- Replace the datasource name with your db name --->
<cffunction name="getStartupQuery" hint="Returns a query recordset for startup">
<cfargument name="datasource" required="no" type="string" default="OtherAppDB">
<!--- Init the query variable --->
<cfset var result = queryNew("id")>
<!-- Get the query dataset --->
<cfquery name="result" datasource="#arguments.datasource#">
YOUR QUERY HERE
</cfquery>
<cfreturn result>
</cffunction>
Application.cfc: (Just the important parts)
<cffunction name="onApplicationStart">
<!--- init the startup.cfc, then retrieve the data
and save it to the application scope. Remember the component name must match
your component above --->
<cfset var startup = createObject("component", "startup")>
<cfset application.varFromOtherDB = startup.getStartupQuery()>
<cfreturn true>
</cffunction>
Now, you should be able to access this variable from any CFM or CFC in your application using:
<cfset myNewVar = application.varFromOtherDB>
or
#application.varFromOtherDB#
IF you use the onApplicationStart() method, I highly recommend implementing a method to reinit the application. For an example, see this other discussion.