Reputation: 293
I would like to store an array or hash in a string field. This field holds instructions for how to use a particular resource. When a person edits the field, I want to capture the date and current user, and store them along with the text the person input. I'm trying to avoid adding extra fields just to capture the date and current user. I would like to simply add one 4000 character text field, and store it there.
It looks like I need to serialize the field in the model. But I'm struggling with how to save the date,current user, and the text in a single field as an array, or a hash if that makes more sense. I created a simple CRUD app to model what I'm trying to do, based on a single model called 'product'. Below is the edit page, and below that is the update function in the controller. How could I capture the current date and user, and store it in the 'description' field? Would this happen in the edit view itself, or should this happen in the update method in the controller?
edit.html.erb
<%= form_for @product do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
<%= f.label :price %><br>
<%= f.text_area :price %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
The model
class Product < ActiveRecord::Base
#validates :name, :price , presence: true
serialize :description
end
The update method
def update
@product = Product.find(params[:id])
if @product.update(product_params)
redirect_to @product
else
render 'edit'
end
end
Upvotes: 1
Views: 1658
Reputation: 27961
It'd be clumsy to try to put this in your view, and your model has no knowledge of current_user
so you'll have to have some code for this in your controller.
I'd recommend actually having a virtual attribute for the display/editing of your actual description text, so in your model:
serialize :description
def desc
self.description? ? self.description[:text] : ""
end
Then in your view you'll have fields for that desc
attribute:
= f.label :desc
= f.text_field :desc
So then in your controller you need to take that :desc
out of the params and insert a :description
instead:
def product_params
p = params.require(:product).permit(:name, :price, :desc)
p.merge description: { text: p.delete(:desc), user: current_user, date: Date.today }
end
Upvotes: 0
Reputation: 1165
First of all, I do not recommend that you pursue this approach unless you have a better reason than "I'm trying to avoid adding extra fields just to capture the date and current user". It will be far easier to manage and maintain this data in the future if you add a field for date
and a foreign key to user
. Your code above should just work if those two fields are present on the product
model.
That being said, it is possible to do this. This is one way you could do it.
def update
@product = Product.find(params[:id])
combined_description = []
combined_description.push(params[:description], params[:current_user], params[:date])
# The next line returns a string representation of the array
product_params[:description] = combined_description.to_s
if @product.update(product_params)
redirect_to @product
else
render 'edit'
end
end
Then, when you need to manipulate this data again in the future, you would have to convert the description string back into an array in order to parse out the current_user and date.
def show
@product = Product.find(params[:id])
# next line returns [description, current_user, date]
description_array = JSON.parse(@product.description)
end
See Array#to_s for the to_s
method docs.
Again, I don't recommend that you follow this approach unless you have a really good reason for doing so. Your life will be far easier if you just add those fields to the product model.
Upvotes: 1