TransientObjectException in grails - grails

I am working on a project and I have two domains.
class Author {
Book book
String name
}
class Book {
Author author
String title
}
I have saved an instance of domain Author in database and in a service I do something like this:
def authorInstance = Author.getById(1)
def bookInstance = new Book(author:authorInstance, title: "Foo")
But i do not save the bookInstance rather, I use it for couple of more processes. This gives me org.hibernate.TransientObjectException. I also tried to do something like:
def authorInstance = Author.getById(1)
def aI = authorInstance
def bookInstance = new Book(aI, title: "Foo")
But in this case too, I get the same error. I am working in this way because I am working in legacy code, so I cannot change much. Is there a work around for this ?

You're apparently changeing some field of authorInstance you set. That's what TransientObjectException says: "object references an unsaved transient instance". Please do read and do quote the error messages.
Save the Author before saving a book. Or do not modify it.
An you probably would like to use hasMany and belongsTo.

By the way, there is another issue with your possible replacement code. Instead of:
def bookInstance = new Book(aI, title: "Foo")
you would need
def bookInstance = new Book(author:aI, title: "Foo")
Book has an in-memory constructor declared which takes a Map object and "author" and "title" are keys into that Map. This constructure then uses the map to initialize class members.

Related

How can I add information to custom user field (Devise)

I create a custom field in user (using a Devise) in my Rails project, varible called information. Type is string.
Somethigh like that: current_user.information
How can I add another string to end of this string?
I need a method then do like this:
current_user.information << some_varible
And save changes.
If the value of current_user.information is a string you can append to it like you stated.
s = current_user.information
s << "New string addition"
s.save
Except the << method mentioned on #Rockwell's answer, you can achieve your goal by using String#concat as well:
s = current_user.information
s.concat("New string addition")
s.save

Rails - dynamic method creation

I have two methods that are identical apart from the ActiveRecord class they are referencing:
def category_id_find(category_name)
category = Category.find_by_name(category_name)
if category != nil
return category.id
else
return nil
end
end
def brand_id_find(brand)
brand = Brand.find_by_name(brand)
if brand != nil
return brand.id
else
return nil
end
end
Now, I just know there must be a more Railsy/Ruby way to combine this into some kind of dynamically-created method that takes two arguments, the class and the string to find, so I tried (and failed) with something like this:
def id_find(class, to_find)
thing = (class.capitalize).find_by_name(to_find)
if thing.id != nil
return thing.id
else
return nil
end
end
which means I could call id_find(category, "Sports")
I am having to populate tables during seeding from a single, monster CSV file which contains all the data. So, for example, I am having to grab all the distinct categories from the CSV, punt them in a Category table then then assign each item's category_id based on the id from the just-populated category table, if that makes sense...
class is a reserved keyword in Ruby (it's used for class declarations only), so you can't use it to name your method parameter. Developers often change it to klass, which preserves the original meaning without colliding with this restriction. However, in this case, you'll probably be passing in the name of a class as a string, so I would call it class_name.
Rails' ActiveSupport has a number of built in inflection methods that you can use to turn a string into a constant. Depending on what your CSV data looks like, you might end up with something like this:
def id_find(class_name, to_find)
thing = (class_name.camelize.constantize).find_by_name(to_find)
...
end
If using a string, you can use constantize instead of capitalize and your code should work (in theory):
thing = passed_in_class.constantize.find_by_name(to_find)
But you can also pass the actual class itself to the method, no reason not to:
thing = passed_in_class.find_by_name(to_find)

How to access property from grails query

I have a domain class called Application as follows:
class Application {
static hasOne = [resumption:Resumption, employee:Employee]
//Employee employee
Date startDate
Date endDate
Integer amountOfDays
String leaveRecommended
String leaveNotRecommended
Date supervisorDate
String toString(){
return "Application for ${employee.lastName}, ${employee.firstName}"
}
}
In the ApplicationController I'm trying to write a query that is going to find all applications that match a particular employee id. I do so as follows:
def applicationlist(){
if(!params.max){
params.max = 10
}
def query
def criteria = Application.createCriteria()
def results
query = { eq("employee_id", Long.parseLong("1")) }
results = criteria.list(params, query)
render(view:"employeeapplicationlist", model:[applicationlist:results])
}
Now I keep getting the error: "could not resolve property: employee_id"
I've checked the generated Application table in MySql, there is a column called employee_id with a value. The weird thing is I can access any other property (like amountOfDays), so what's the deal with employee_id? Why is it complaining that it cannot resolve the property? What am I missing? Thanks in advance.
Associations in the criteria DSL are of the form
Application.withCriteria{
employee{
eq 'id', 1
}
}
http://grails.org/doc/latest/guide/GORM.html#criteria
But you could probably just do:
def employee = Employee.proxy(1)
Application.findAllByEmployee( employee )
This appears a few times in the Grails User Guide as 'querying associations'
Oh well it looks like I'm still not fully adjusted to interfacing with the database on an Object level. For anyone else with this or a similar problem, here's the fix:
query = { eq("employee.id", Long.parseLong("1")) }
Sine the Application Domain class has one Employee, then we just need to access the id field of that employee. Remember we're in the ApplicationController.

Struct with types and conversion

I am trying to accomplish the following in Ruby:
person_struct = StructWithType.new "Person",
:name => String,
:age => Fixnum,
:money_into_bank_account => Float
And I would like it to accept both:
person_struct.new "Some Name",10,100000.0
and
person_struct.new "Some Name","10","100000.0"
That is, I'd like it to do data conversion stuff automatically.
I know Ruby is dinamically and I should not care about data types but this kind of conversion would be handy.
What I am asking is something similar to ActiveRecord already does: convert String to thedatatype defined in the table column.
After searching into ActiveModel I could not figure out how to to some TableLess that do this conversion.
After all I think my problem may require much less that would be offered by ActiveModel modules.
Of course I could implement a class by myself that presents this conversion feature, but I would rather know this has not yet been done in order to not reinvent the wheel.
Tks in advance.
I think that the implementation inside a class is so easy, and there is no overhead at all, so I don't see the reason to use StructWithType at all. Ruby is not only dynamic, but very efficient in storing its instances. As long as you don't use an attribute, there is none.
The implementation in a class should be:
def initialize(name, age, money_into_bank_account)
self.name = name
self.age = age.to_i
self.money_into_bank_account = money_into_bank_account.to_f
end
The implementation in StructWithType would then be one layer higher:
Implement for each type a converter.
Bind an instance of that converter in the class.
Use in the new implementation of StructWithType instances (not class) the converters of the class to do the conversion.
A very first sketch of it could go like that:
class StructWithType
def create(args*)
<Some code to create new_inst>
args.each_with_index do |arg,index|
new_value = self.converter[index].convert(arg)
new_inst[argname[index]]= new_value
end
end
end
The ideas here are:
You have an instance method named create that creates from the factory a new struct instance.
The factory iterates through all args (with the index) and searches for each arg the converter to use.
It converts the arg with the converter.
It stores in the new instance at the argname (method argname[] has to be written) the new value.
So you have to implement the creation of the struct, the lookup for converter, the lookup for the argument name and the setter for the attributes of the new instance. Sorry, no more time today ...
I have used create because new has a different meaning in Ruby, I did not want to mess this up.
I have found a project in github that fulfill some of my requirements: ActiveHash.
Even though I still have to create a class for each type but the type conversion is free.
I am giving it a try.
Usage example:
class Country < ActiveHash::Base
self.data = [
{:id => 1, :name => "US"},
{:id => 2, :name => "Canada"}
]
end
country = Country.new(:name => "Mexico")
country.name # => "Mexico"
country.name? # => true

How do I convert a string to a class method?

This is how to convert a string to a class in Rails/Ruby:
p = "Post"
Kernel.const_get(p)
eval(p)
p.constantize
But what if I am retrieving a method from an array/active record object like:
Post.description
but it could be
Post.anything
where anything is a string like anything = "description".
This is helpful since I want to refactor a very large class and reduce lines of code and repetition. How can I make it work?
Post.send(anything)
While eval can be a useful tool for this sort of thing, and those from other backgrounds may take to using it as often as one might a can opener, it's actually dangerous to use so casually. Eval implies that anything can happen if you're not careful.
A safer method is this:
on_class = "Post"
on_class.constantize.send("method_name")
on_class.constantize.send("method_name", arg1)
Object#send will call whatever method you want. You can send either a Symbol or a String and provided the method isn't private or protected, should work.
Since this is taged as a Ruby on Rails question, I'll elaborate just a little.
In Rails 3, assuming title is the name of a field on an ActiveRecord object, then the following is also valid:
#post = Post.new
method = "title"
#post.send(method) # => #post.title
#post.send("#{method}=","New Name") # => #post.title = "New Name"
Try this:
class Test
def method_missing(id, *args)
puts "#{id} - get your method name"
puts "#{args} - get values"
end
end
a = Test.new
a.name('123')
So the general syntax would be a.<anything>(<any argument>).

Resources