serialized object not being converted - ruby-on-rails-3

I have a Model called statistics which has a value field that contains Goals (a self defined class) data
class Statistic < ActiveRecord::Base
serialize :value
end
When I try to access the goals_against (an atr_reader of the Goals class) I get
undefined method `goals_against' for #<String:0x54f8400>
The value property contains following data:
--- !ruby/object:Goals \ngoals: {}\n\ngoals_against: 1\ngoals_for: 0\nversion: 1\n
In string format according to the debugger.
It seems that rails doesn't know this data is of type Goals.
Someone knows how to solve this?
Thanks

Three things:
First, where ever your Goal class is defined, make sure it is loaded. At some point Rails stopped auto-loading stuff in the lib folder. So where ever your extra classes are located, set them in config.autoload_paths (in config/application.rb).
Second, when you declare a column as serialized, you have the option of specifying the class. This is especially useful when you are working with a custom class and you want to make sure Rails does the conversion correctly.
serialize :value, Goal
Third, when you have a column that is serialized, make sure you have enough room for it. In other words, most of the time you're going to want that column to be "text" and not "string" in your schema (otherwise your sql engine will silently truncate anything too large to fit in a string column and you'll end up saving a broken object).

Related

How to call remove_column on SALV table?

I want to execute the method remove_column on an instance of cl_salv_column_table but because of its visibility level, I am not able to do so.
Plan:
I already tried inheriting from cl_salv_columns_list and then perform the call inside the remove-method:
CLASS lcl_columns_list DEFINITION INHERITING FROM CL_SALV_COLUMNS_LIST.
PUBLIC SECTION.
METHODS:
remove IMPORTING iw_colname TYPE string.
ENDCLASS.
But apparently my casting knowledge got rusty as I'm not able to figure out an appropriate solution.
This is my current hierarchy - the red arrows show the way I would have to take:
My approach looks like this:
DATA lo_column_list TYPE REF TO lcl_columns_list.
lo_column_list ?= CAST cl_salv_columns_list( lo_columns ).
But it fails with:
CX_SY_MOVE_CAST_ERROR
Source type: \CLASS=CL_SALV_COLUMNS_TABLE
Target type: "\PROGRAM=XXX\CLASS=LCL_COLUMNS_LIST"
Background:
My task is to select all columns of 3 tables (which would be done like SELECT t1~*, t2~*, t3~* ...) as long as their names don't conflict (e.g. field MANDT should only be displayed once). This would require defining a very big structure and kick the size of the selection list to a maximum.
To avoid this, I wanted to make use of the type generated by my inline-declaration. Hiding the individual columns via set_visible( abap_false ) would still display them in the layout manager - which looks really ugly.
Is there any other way to accomplish my target?
Use set_technical( abap_true ) to hide the columns entirely. As for your approach - sorry, inheritance does not work that way - in no statically typed object oriented language that I know. You can't 'recast' an instantiated object to a different class. You would need to modify the framework extensively to support that.

Design patterns on initializing an object?

What's the recommended way to handle an object that may not be fully initialized?
e.g. taking the following code (off the top of my head in ruby):
class News
attr_accessor :number
def initialize(site)
#site = site
end
def setup(number)
#number = number
end
def list
puts news_items(#site, #number)
end
end
Clearly if I do something like:
news = News.new("siteA")
news.list
I'm going to run into problems. I'd need to do news.setup(3) before news.list.
But, are there any design patterns around this that I should be aware of?
Should I be creating default values? Or using fixed numbers of arguments to ensure objects are correctly initialized?
Or am I simply worrying too much about the small stuff here.
Should I be creating default values?
Does it make sense to set a default? If so this is a perfectly valid approach IMHO
Or using fixed numbers of arguments to ensure objects are correctly initialized?
You should ensure that your objects cannot be constructed in an invalid state, this will make your's and other users of your code much simpler.
in your example not initializing number in some way is a problem, and this method is an example of temporal coupling. You should avoid this, and the two ways you suggested are ways to do this. Alternatively you can have another object or static method responsible for building your object in a valid state instead
If you do have an object which in not fully initialised then any invalid methods should produce appropriate and descriptive exceptions which let the users know that they are using the code incorrectly, and gives examples of the correct usage patterns.
In c# InvalidStateException is usually appropriate and similar exceptions exist in Java. Ruby is beyond my pay grade unfortunately :)

Yii CActiveRecord with Column Named "attributes"

I used the CRUD generator from a legacy database. When searching for a column value I get the following error:
htmlspecialchars() expects parameter 1 to be string, array given (/usr/local/share/yii/framework/web/helpers/CHtml.php:103)
The problem is that the model has an existing column named "attributes" which is creating a conflict. I removed the entry from the _search.php and commented out all instances in the model hoping to at least get it working but no luck. Any suggestions would be appreciated.
Thanks.
Every CActiveRecord instance (or CModel instance for that matter) has a getter/setter named attributes with which all the attributes can be set. This leads to a conflict because the generated crud code uses the attributes attribute expecting it works as described before.
The controller does something like:
$model->attributes=$_POST['ModelClassName'];
// or
$model->attributes=$_GET['ModelClassName'];
This is meant to set al the (safe) attributes of the model at once. Instead this overwrites the database attribute attributes of your legacy DB model.
This in turn leads to the error you describe, because $_GET['ModelClassName'] and $_POST['ModelClassName'] typically contain arrays of data.
I guess the easiest fix would be to directly call the setter function for the "normal" attributes behavior which would lead to replacing the lines mentioned above with something like the following:
// in the controller
$model->setAttributes($_POST['ModelClassName']);
// and
$model->setAttributes($_GET['ModelClassName']);
I think rest of the generated CRUD code (the views) could and should be left untouched to make it work.
If you want to know how and why this works, it's best to do some research into the __get and __set magic functions and how they're used in the yii framework.

How to manually instantiate ActiveRecord truncated objects?

Working with ActiveRecord and JRuby, I try to invoke a stored procedure on a Database. Using the underlying Java Library I reached a point where I have a hash with the columns specified in the select.
Now I'd like to use this hash to have ActiveRecord models, but I'd like them to look like if I did a classic Model.select(columns).all (with only the columns values, errors when trying to reach the other ones and readonly).
There must be something inside of AR to do this but I can't find anything and all my search leads to all the basic "fetch" tutorials ...
OK so I kept digging in Rails code and figured out my answer was the instantiate method.
The idea is if you are inside a model called MyModel and do this
object = instantiate(value1: 1, value2: 'ok')
you will have an instance of the MyModel class with theses attributes defined. If the model is supposed to have more columns, they are not defined. The object is readonly.

Newbie question: how do I create a class to hold data in Visual Basic Studio?

I'm really sorry. This must seem like an incredibly stupid question, but unless I ask I'll never figure it out. I'm trying to write a program to read in a csv file in Visual Basic (tried and gave up on C#) and I asked a friend of mine who is much better at programming than I am. He said I should create a class to hold the data that I read in.
The problem is, I've never created a class before, not in VB, Java, or anything. I know all the terms associated with classes, I understand at a high level how classes work no problem. But I suck at the actual details of making one.
So here's what I did:
Public Class TsvData
Property fullDataSet() As Array
Get
Return ?????
End Get
Set(ByVal value As Array)
End Set
End Property
End Class
I got as far as the question marks and I'm stuck.
The class is going to hold a lot of data, so I made it an array. That could be a bad move. I don't know. All i know is that it can't be a String and it certainly can't be an Integer or a Float.
As for the Getter and Setter, the reason I put the question marks in is because I want to return the whole array there. The class will eventually have other properties which are basically permutations of the same data, but this is the full set that I will use when I want to save it out or something. Now I want to return the whole Array, but typing "Return fullDataSet()" doesn't seem like a good idea. I mean, the name of the property is "fullDataSet()." It will just make some kind of loop. But there is no other data to return.
Should I Dim yet another array inside the property, which already is an array, and return that instead?
Instead of writing your own class, you could get yourself familiar with the pre-defined class System.Data.DataTable and then use that for holding CSV data.
In the last few years that I've been programming, I've never actually used a multi-dimensional array, and I'd advise you not to use them, either. There's usually ways of achieving the same with a better data structure. For example, consider creating a class (let's call it CsvRecord) that holds only one record; that is, only one line from the CSV file. Then use any of the standard collection types from the System.Collections.Generic namespace (e.g. List(Of CsvRecord)) to hold the entire data (ie. all lines) in the CSV file. This effectively reduces the problem to, "How do I read in one line of CSV data?"
If you want to take suggestion #2 even further, do as cHao says and don't simply lay out the information you've read as a CsvRecord; instead, create an object that reflects the actual content. For example, if your CSV file contains product–price information, call your CSV record class ProductInfo or something more fitting.
If, however, you want to go on with your current approach, you will need a backing field for the property, as demonstrated by Philipp's answer. Your property then becomes a "façade" that only delegates to this backing field. This is not absolutely necessary: You could simply make the backing field Public and let the user of your class access it directly, though that is not considered a good practice.
Ideally, you ought to have a class representing the specific data you want to read in. Setting an entire array at once is asking for trouble; some programs that read {C,T}SV files will freak out if all rows don't have the same number of columns, which is exceedingly easy to do if you can set the data to be an array of arbitrary length.
If you're trying to represent arbitrary data, frankly, you'd do just as well to use a List(Of String). If it's meant to be a table, you could instead read in the first line and make it a list as above (let's call it "headers"), and then make each row a Dictionary(Of String, String). (Let's call each row "row", and the collection (a list of these dictionary objects) "rows".) Just read in the line, split it like you did the first, and say something like row(headers(column number)) = value for each column, and then stuff it into 'rows'.
Or, you could use the data classes (System.Data.DataTable and System.Data.DataSet would do wonders here).
Usually you use a private member to store the actual data:
Public Class TsvData
Private _fullDataSet As String()
Public Property FullDataSet() As String()
Get
Return _fullDataSet
End Get
Set(ByVal value As String())
_fullDataSet = value
End Set
End Property
Note that this is an instance of bad design since it couples a concept to a concrete representation and allows the clients of the class to modify the internals without any error checking. Returning a ReadOnlyCollection or some dedicated container would be better.