using form data as text - ruby-on-rails

i am trying to use form data outside of just form elements. i want to show form data as normal text.
controller:
#addresses = ['Billing', 'Shipping']
#addresses.each do |a|
addresses.build(:address_type => a)
end
then within my form...for example...(haml)
- fields_for :addresses do |a|
a.address_type #to just render 'Billing', etc.
or...
- fields_for :addresses do |a|
%div{:class => a.address_type
would i need to make a custom formbuilder method? or is there an existing way

can't understand what you're looking for. that code doesn't seem correct at all. if #addresses is an array of elements, how do you expect it has any ActiveRecord methods?
EDIT:
if you want to render just the data, even if the object is not saved, it's not a problem:
in the controller you'll build the object:
...
addresses.build(:address_type => a)
...
then, in the view, use that data:
<some tag>
<%= #object.address_type %>
</some tag>
With a better example, I can explain better, but I hope you understand ;)

discovered the object method!
- form_for #addresses do |a|
%h1= a.object.address_type

Related

Rails only pass params that have changed on edit submit

I have a edit form that prepopulates with the current values. Its a custom edit screen (not the default one that rails uses) and what Im using it for is for users to submit changes that will get voted on and might eventually get applied to the record. However, in the time it takes to be voted on something else might have changed and I dont want to overwrite the changes if they didnt submit a change.
EDIT: Changing to my more specific case so hopefully answers will work for it...
I have the following tables: Recipes, RecipeIngredients, RecipeSteps, RecipeChanges. On the show view of my recipes it displays all the ingredients/steps and there is a tab that then changes just the ingredients/steps to forms as to allow the user to submit changes. I dont want these changes applied though. Instead Im trying to create a voting system where people can vote on them. So what I have decided on is to convert the parameters from the form into a json string and save it in the RecipeChanges table under a single column (instead of using two table for ingredient changes and step changes). Heres the code for the form (html removed to make it easier to see the rails stuff):
<%= form_for #recipe, url: recipe_recipe_changes_path(#recipe), html: {method: "post"}, remote: true do |f| %>
<%= f.fields_for :recipe_ingredients, f.object.recipe_ingredients.order(:order) do |ff| %>
<%= ff.hidden_field :order, class: "position" %>
<%= ff.text_field :ingredient, placeholder: "Add Ingredient (e.g. 3 cups cooked rice)" %>
<label><%= ff.check_box :_destroy %>Remove</label>
<% end %>
<%= f.fields_for :recipe_steps do |ff| %>
<%= ff.hidden_field :order, class: "position"%>
<%= ff.text_area :step %>
<label><%= ff.check_box :_destroy %>Remove</label>
<% end %>
<%= submit_tag "Submit", class: "button" %>
<% end %>
So this sends a recipe object to my RecipeChange controller and there I handle the params to save them as the json string like so:
def create
#change = RecipeChange.new
#change.recipe_id = params[:recipe_id]
#change.new_recipe = recipe_change_params.to_json
#if #change.save
#add alert for successfully adding
#else
# add code for error handling
#end
end
This works like I want except for it saves all the ingredients/steps and I would like to only save what they have changed. I had two thoughts on how to do this but not sure how to accomplish it.
Check if the fields have changed when they click the submit button and only send the ones that have been edited (not sure if possible)
In the controller grab the original recipe (I have the id so that would be easy) and loop through the ingredients/steps and compare them and remove any that are identical....this is the method I think would be better but not sure how to loop through the hashes to accomplish this
Have a look at ActiveModel::Dirty. http://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-changed
You can do something like:
changes = bag.changed_attributes and get a hash of that attributes that changed, and then save those with bag.update_attributes(changes), for example.
This is a bit old now but I've come across the same or similar scenario and wanted to share for others.
In my case I populate some nested form fields based on an existing object in my #new action. However, in my #create action I did not want to save these nested form params unless they were actually modified compared to the original existing object.
In this case, ActiveModel::Dirty would always be true as it would compare [nil, "value"].
I first tried to modify the params in my #create action and compare them to the original existing object similar to this discussion but this got messy and felt wrong.
I ended up saving all records then doing a cleanup with an instance method in my model that I call after save in my controller's #create action. Still feels a bit dirty but it's working.
Example:
# controllers/changes_controller.rb
# ChangeController#create
def create
# ... shortened for example ...
if #instance.save
#instance.remove_clean_changes
format.html
end
end
# models/change.rb
# Change#remove_clean_changes
# Loop over all original objects and compare the necessary attributes
# to the changes. If they match, they are clean and should be deleted.
def remove_clean_changes
original_objects = self.original_objects
changes = self.changes
original_objects.each do |original_object|
changes.each do |change|
change.destroy if (change.attribute_one == original_object.attribute_one &&
change.original_object_id == original_object.id)
end
end
end

Access attributes in controller while looping in view

I have a loop in my view:
<% #deals.each do |d| %>
<% end %>
Deal and ListItem share the :code attribute.
If I wanted to count all the list_items that shared :code with a certain deal, how can I do this in the controller while iterating through the loop?
I understand it's bad form to access Models in the view correct? So that would rule out doing something like this in the loop right?:
<%= "#{ListItem.where(:code => d.code).count}" %>
Can I use a variable or some custom method to achieve this? Please let me know if I can clarify. Thank you!
You want to do all the calculation on the server in your controller action before rendering the view.
So in addition to gathering the #deals, you will also set an instance variable for the count.
def index
#deals = Deals.all # or whatever your finder is
#common_listitem_count = ListItem.where(code: #deals.pluck(:code)).count
end
Then just call the count instance variable in the view:
<%= #common_listitem_count %>

Rails - json.erb template

I have been trying to figure out a way to customize JSON with special fields, custom formats, etc etc. I have created an as_json and to_xml method in my model to formulate the object how I need. This works well but it is sloppy because some of my helper methods had to move into the model, because I need the formats in the helpers and model. I also think it is sloppy code and makes the model out of control.
I have been able to get a format with json.erb working but don't think it is working 100% correct either and the callback doesn't append either. Anyone get this working
Here is what I got so far.
api calls format.json
template called is items.json.erb
<% #items.each do |item| %>
<%= { :item => { :id => item.id, :name => item.name }.to_json.html_safe %>
<% end %>
This works but seems odd. Anyone have suggestions or have a way to do this?
btw did this for the callback to work
<%= params[:callback]+"(" if params[:callback] %>
<% #items.each do |item| %>
<%= { :item => { :id => item.id, :name => item.name }.to_json.html_safe %>
<% end %>
<%= ")" if params[:callback] %>
I think the best way to do this would be to skip the erb template if you don't absolutely need if for some reason. Then you could do something like this:
items = Item.all
render :json => items.to_json(:only => [:id, :name]), :callback => params[:callback]
You can override the to_json method in your model to add fields or call methods.
Based on your answer to polarblau, you should override the as_json method and use the :methods parameter to include method results in your json
class Item
def date
return "1 year and 8 months" #obviously use logic here
end
def as_json(args={})
super(:methods=>[:date], :only=>[:id=>:name])
end
end
Most likely, you'll want to either:
use custom finder sql to alter column names/perform calculations (it's much faster than Ruby):
MyModel.select('col_name_that_needs_renamed AS new_name').order('some_col DESC')
or a more complicated example:
MyModel.find_by_sql('SELECT col_name_that_needs_renamed AS new_name, foo_col*50 AS math WHERE foo=bar ORDER some_col LIMIT 8')
if there's something you can't do (or can't figure out) in SQL, you may have to revert to Ruby (although not recommended because it's significantly slower)
API Dock for to_json

Rails: How to store form params in a non-active record model?

I want to do store the parameters from a form in a model. Since I don't want the model to use any database, it does not inherit from ActiveRecord::Base. I'm thinking it should look something like this:
# in view:
<% form_for :question, :url => {:action => "ask"} do |f| %>
<%= f.text_field(:q) %>
<%= submit_tag %>
<% end %>
# in controller:
def ask
# I want this to magically set all variables in #question using
# values from params.
#question = params[:question]
end
# in model:
class Question
attr_accessor :q
def initialize
#q = ""
end
end
But after spending 1½ days on it, it doesn't seem to be the right way to do it. Any suggestions would be much appreciated.
Take a look at this article:
http://pullmonkey.com/2008/1/6/convert-a-ruby-hash-into-a-class-object
It shows how to create a class that will dynamically create a class from the passed in Hash.
Even if you set your Question properly, how do you plan to persist this? A file?
I think it is a much better approach to get a deep understanding of ActiveRecord before going for fancy models that have custom persistence
You might want to check out Ryan Bates' Railscast on creating a non ActiveRecord model
http://railscasts.com/episodes/121-non-active-record-model
... however I'd suggest that if you're thinking RESTfully about this, it sounds from your comment to Sam's answer like you may have another RESTful resource at work - i.e. you don't actually want to use a QuestionsController... but instead something to do with what you're actually creating (the method call you mention). You can still initialize your Question object as part of that process.

ruby on rails form_for

I have a calendar_date_select in a view that shows a table listing all the information on a certain phone. I want to add a To: and From: date range that a user can select and update the table in the view. The structure is like this:
Usage Controller
Detail action in the usage controller that shows the call history from a certain phone.
Inside detail I want the To and from fields with a refresh button.
What is exactly happening in this code:
<% form_for :date_range do |f| %>
<%= f.calendar_date_select :start, :time => true %>
<%= f.calendar_date_select :end, :time => true %>
<%= f.submit "Submit" %>
<% end %>
Does this pass a hash to the usage controller and look for a date_range method? My current route looks like this
usage/detail/id-of-phone
I would like it to look something like this:
usage/detail/id-of-phone#start-end
So I could then (I think) extract the start and end dates from the params with just params[:start] and params[:end]. Am I doing this right, or is there a better way to get the desired result that I want.
I haven't used the calendar_date_select plugin, but you should be getting the parameters back already.
params[:date_range][:start]
params[:date_range][:end]
What you want is the url or the smart solution to get the params?
Please set the routes.rb for the url. Or you can make many method in the 'DataRange' model.
As many programmers using, save many dates in the model. But making us terrible is using the params smartly.
Such as
class Model
def start
......
end
def end
......
end
end
You can't get the params by params[:start] if you pass the params by the form. You can see the form's html for detail.
Please use the
params[:...][:start]

Resources