I have an Article model. The database schema has several columns including 'title'. I am trying to provide my own getter in place of the method_missing-provided getter. At present I am trying simply:
class Article < ActiveRecord::Base
def title
"blah"
end
end
but when I reload the view the title field continues to be sourced from the database. (My server environment is development and I'm riding Rails 3.1.0.) Any ideas?
Input helpers don't use the normal accessor if there is a 'before_type_cast' variant, so in your case, it is accessing title_before_type_cast.
Either also define that, or choose another method name altogether. I would advise the latter, because overriding accessors is confusing, even without this complication. Don't fight ActiveRecord, you won't win.
Related
Is there any gem/plugin for ruby on rails which gives the ability to define custom fields in a model at runtime with no need to change the model itself for every different field.
I'm looking for something like Redmine acts_as_customizable plugin which is packaged as a gem usable in the rails way, i.e.
gem 'gemname'
rails g something
rails db:migrate
class Model < ActiveRecord::Base
acts_as_something
end
Here are the CustomField and the CustomValue classes used in Redmine.
Edit:
Since my question is not clear I add a brief use case which explains my need better:
I want users to be able to design their own forms, and collect data
submitted on those forms. An important decision is the design of how
these custom dynamic records are stored and accessed.
Taken from here, in this article approach the problem with different ideas, but they all have drawbacks. For this reason I'm asking if the issue has been approached in some gem with no need to rethink the whole problem.
I'm not aware of a gem that does this, but serialize works quite well and it's a built-in. You get a NoSQL-ish document store backed by JSON/YAML.
If you allow user to create a custom form, you can pass nested arrays et cetera directly into the attribute. However, if you need to validate the structure, you're on your own.
I'm afraid it could be tricky and complicated to do it in ActiveRecoand (generally in standard relational database). Take a look at http://mongoid.org/docs/documents/dynamic.html - this mechanism is using nosql feature.
You can also may try the following trick:
1/ Serialize a hash with your custom fields in the database column, for example { :foo => 'bar', :fiz => 'biz' }
2/ After load a record from database do some metaprogramming and define corresponding methods on the record's singleton class, for instance (assume that custom fields are stored and serialized in custom_fields column):
after_initialize :define_custom_methods
# ..or other the most convinient callback
def define_custom_methods
# this trick will open record's singleton class
singleton_class = (class << self; self; end)
# iterate through custom values and define dynamic methods
custom_fields.each_with_key do |key, value|
singleton_class.send(:define_method, key) do
value
end
end
end
Since rails 3.2 you can use store method. Just include following in your model:
store :properties, accessors: [:property1, :property2, :property3...]
You only need to change your model once (to add properties field to db table). You can add more properties later without altering the schema.
The way this works is by serializing properties hash into YAML and saving it into database. It it suitable for most cases, but not if you'd like to use these values in db queries later.
I don't know a gem, but this can be accomplished be creating a table called custom_fields with a name column and possibly a datatype column if you wanted to restrict fields by datatype.
Then you create a join table for a custom field to your desired table and a value and do whatever validations you want.
I am new to ruby and rails and I am having difficulty conceptualizing the MVC techniques in conjunction with database views. I am dealing with a legacy database that has several viiews that are used to generate reports.
Where I get lost is how do I actually use a database view. Should it be put in a model? If so what exactly would that look like?
As an example the legacy db has a view called qryTranscriptByGroup. It is used in the legacy application in an SQL statement such as "SELECT * FROM qryTranscriptByGroup WHERE group='test_group'". This returns a small number of records usually less than 100.
If i create a model, Transcript, how would I define a method like Transcript.find_by_group(group)? As well, it would seem that I might need to prevent any other "find" methods as they would be invalid in this context.
There is also the the fact that the view is read-only and I would need to prevent any attempts to create, update or destroy it.
Perhaps I am going about this entirely the wrong way. The bottom line is that I need to get information from several tables (models?) that represent the information about a user (a transcript). Actually one or more users (transcripts plural).
-Thanks!
You can use a database view like a normal model.
In your case:
class Transcript < ActiveRecord::Base
set_table_name "qryTranscriptByGroup"
set_primary_key "if_not_id"
end
The query will be then:
Trascript.find_by_group('test_group')
without you need to declare anything.
Rails uses the method_missing method to magically generate find_by_column_name methods.
For the create/update/delete action you can simply delete them or not create them in the controller.
I'm working through the Ruby on Rails tutorial and just made a Comment model with three properties.
rails generate model Comment commenter:string body:text post:references
It generated an ActiveRecord class with post but not commenter and body.
class Comment < ActiveRecord::Base
belongs_to :post
end
Why doesn't rails formally define the non-reference properties anywhere other than the DB migration scripts?
Rails dynamically loads attributes - specifically, the names of the columns and their types - based on the database schema. There is no need to define or declare them in your models. For apps running in production, it does this once, at load time. For development, it will reload them as often as every request, but only loads them when each model is used.
Rails does not infer other things from your database, though. For instance, if you were to place a unique index on a name column, it would not automatically add a validates_uniqueness_of :name to your model. Of course, the database would still enforce this constraint when you save the record, causing an exception to be raised should the name field contain a duplicate value. The recommendation, in this case, is to do both.
Why doesn't rails formally define the non-reference properties anywhere other than the DB migration scripts?
Well, where do you need them "defined" anyways? Migrations are the only place where these attributes matter coz its responsibility is to create database tables with those attributes.
If you do a scaffold on comments with similar parameters, it would also generate the views and it would be using the attributes. They don't need to be "defined" as such anywhere else.
The short answer to your question is "no". Even the migration is not a definitive place to look as there might be many migrations related to a model.
However, you may have a look at the generated "db/schema.rb" which is an aggregation of all migrations. It contains the schema definition of all activerecord models. This maybe your best bet.
Additionally, you may want to use the https://github.com/ctran/annotate_models plugin that inserts a comment in your model to help you keep track of all your model's attributes.
I have just started with Rails and coming from a .net background I find the model inheriting from ActiveRecord is hard to understand, since the don't contain the corresponding attributes for the model. I cannot imagine a new developer exposed to a large code where the models only contains references to other models and business logic.
From my point of view the DataMapper model is much easier to grasp but since ActiveRecord is the defacto standard it feels weird to change the ORM just for this little problem.
DataMapper
class Post
include DataMapper::Resource
property :id, Serial # An auto-increment integer key
property :title, String # A varchar type string, for short strings
property :body, Text # A text block, for longer string data.
property :created_at, DateTime # A DateTime, for any date you might like.
end
ActiveRecord
class Post < ActiveRecord::Base
end
I'm not sure if this is an issue and that people get used to the models without attributes, or how does experienced rails user handle this?
I don't think using the database manager or looking at loads of migrations scripts to find the attributes is an option?
Specifying attr_accessible will make the model more readable but I'm not sure if it's a proper solution for my problem?
Check out the annotate_models plugin on github. It will insert a commented schema for each model in a comment block. It can be installed to run when migrate is.
You don't have to "look at loads of migration scripts to find the attributes" - they're all defined in one place in db/schema.rb.
A few tips:
Load up the Rails console and enter
Post.column_names for a quick
reminder of the attribute names.
Post.columns gives you the column
objects, which shows the datatypes
db/schema.rb contains all the
migration code in one place, so you
can easily see all the column
definitions.
If you are using a
decent editor/IDE there should be a way to
allowing you to jump from the model file
to the migration file. (e.g. Emacs
with ROR or Rinari)
I have an existing database(Postgresql). How can i create models from it? How can i pass column names for Rails? As if something like this:
Person:
Name :table_name_for_name_attribute
Surname :table_name_for_surname_attribute
PersonalCode :table_name_for_perconal_code_attribute
Unfortunately, my database is not following Rails convention, because not all tables are named in English. Any ideas how can i map it?
UPDATE reverse_scaffold script generates only model, but i need controller and view forms also.
You can define a table name not matching the model's using the table_name method.
class MyModel < ActiveRecord::Base
def self.table_name
'my_table_name'
end
end
Change the value of 'my_table_name' to your effective table name.
For generating controllers and views with automatic methods to create, update, delete and view database objects, you should create a scaffold. There's some pretty good documentation on the rails guides about that.
In your model, you'll need to tell ActiveRecord what the table name and primary key field column is named if they don't follow the conventions.
class MyLegacyTable < ActiveRecord::Base
self.table_name = "some_name"
self.primary_key = "some_name_primary_key_field"
end
Once you've done that, ActiveRecord knows the some_name_primary_key_field as id, which makes life much easier.
Rails doesn't need to know the column names it figures them out when it connects to the database.
As others have said you can specify a table name in the model.
As for generating controllers/views, you're pretty much own your own. script/generate scaffold is deprecated. It still works as far as creating things, but you need to pass all column names and times on the command line.
Instead have a look at the ActiveScaffold Plugin, it has a similar end result. But is much more robust and easier to adapt to model changes.