Auto set value of nested attributes in Rails - ruby-on-rails

I have a model location which has many messages. I am trying to let users who are browsing locations to send messages to location owners.
I have location.rb
has_many :messages
accepts_nested_attributes_for :messages
and message.rb
belongs_to :location
In locations_controller.rb
def location_params
params.require(:location).permit(:name,
:user_id,
:image,
:latitude,
:longitude,
location_images_attributes: [:id, :location_id, :location_image, :_destroy],
messages_attributes: [:id, :location_id, :from_email, :to_email, :content])
end
Currently i have in my view the following code:
<%= simple_form_for #location do |l| %>
<%= l.simple_fields_for :messages, #location.messages.build do |m| %>
<%= m.input :content %>
<%= m.input :to_email, :input_html => {:value => #location.user.email}, as: :hidden %>
<% end %>
<%= l.button :submit %>
<% end %>
I don't want to set the value of the email field via hidden field, but i want to pass value from controller. Or a model. Please advise.

Maybe try this approach in your Location model:
class Location < ActiveRecord::Base
has_many :messages, after_add: :set_email
accepts_nested_attributes_for :messages
def set_email(message)
message.to_email = user.email
end
end
Basically you have to register a method for Location, when new message is added to messages set.
In this example I named it set_email, which takes the message object as it's argument, and you can freely modify it. I'm just setting the to_email based on location's email.
Hope this solves your problem!

You could do something like this in the Message model:
before_create :set_to_email
def set_to_email
self.to_email = self.location.user.email
end
Downside is that on every create action a few additional database lookups are being performed. So on the grand scale this is not an ideal solution in terms of performance optimization.

Related

Rails 4 nested form issue

Hi I'm using the nested form plugin and trying to make it work for rails 4 instead of rails 3. Basically my model looks like this:
has_many :item, :dependent => :destroy
accepts_nested_attributes_for :item, :reject_if => lambda { |a| a[:item].blank? }, :allow_destroy => true
and my view looks like this:
<%= nested_form_for(#store) do |f| %>
<%= f.fields_for :item do |item_form| %>
<%= item_form.text_field :name %>
<%= item_form.link_to_remove "Remove this item" %>
<% end %>
<% end %>
this works (in terms of presentation - you can add and delete fields like you should be able to) but doesn't save the item names.
I tried this in my controller (these are the protected attributes/params):
def store_params
params.require(:store).permit(:name, :owner, :description,:url, :user, item_attributes)
end
but it still comes up with:
Unpermitted parameters: item_attributes
Thanks for all help!
You're going to have to permit the fields of item (like name) to be allowed as well.
So try this:
def store_params
params.require(:store).permit(:name, :owner, :description,:url, :user, item_attributes: [:name])
end
sometimes you have to specify the :id like this:
def store_params
params.require(:store).permit(:name, :owner, :description,:url, :user, item_attributes: [:id, :name])
end
in a similar case I had last week, not specifying the :id made Rails 4 create an new entity instead of updating the existing one.

foreign key not updating

I'm developing an app for college where a user can log on & upload details of a hiking trail.
So far everything is working & I have also implemented a nested form for photos in each hiking trail. A user can log-on & create a hike.
I would like to display all the hikes which the user created in there show/profile page but when I've set up the relationships in my database & the has_many & belongs_to options in my model. I've also tried to do this with nested accepts_nested_attributes_for :hikingtrails it does none of this works.
I've checked my database when a hikingtrail is created by a user it is not updating the user_id field in the table.
I'm not sure if I'm approaching this entirely the wrong way, should I be looking at polymorphic associations?
class User < ActiveRecord::Base
attr_accessible :user_name, :email, :password, :password_confirmation, :photos_attributes, :hikingtrails_attributes
has_many :hikingtrails
accepts_nested_attributes_for :hikingtrails, :allow_destroy => :true, :reject_if => :all_blank
class Hikingtrail < ActiveRecord::Base
attr_accessible :description, :name, :looped, :photos_attributes,:directions_attributes, :user_id
has_many :photos
has_many :trails
has_many :directions
belongs_to :user
users/show.html.erb
<div class="page-header">
<h1>Your Profile</h1>
</div>
<p>
<b>username:</b>
<%= #user.user_name %>
</p>
<p>
<b>email:</b>
<%= #user.email %>
</p>
<h4>Small Photos</h4>
<% #user.photos.each do |photo| %>
<%= image_tag photo.image_url(:thumb).to_s %>
<% end %>
<h4>Hiking Trails</h4>
<% #user.hikingtrails.each do |hk| %>
<%= hk.name %>
<% end %>
<%= link_to "Edit your Profile", edit_user_path(current_user), :class => 'btn btn-mini' %>
You didn't add :user_id to your accessible attributes in the Hikingtrail model. Try the following:
attr_accessible :description,
:duration_hours,
:duration_mins,
:name,
:looped,
:addr_1,
:addr_2,
:addr_3,
:country,
:latitude,
:longitude,
:photos_attributes,
:trails_attributes,
:directions_attributes,
:user_id
UPDATE:
After seeing the form code, I think it's probably not necessary to do the above and could potentially also be unsafe. Instead, don't set the user_id through mass assignment, but handle user assignment in your controller like so:
class HikingtrailsController < ApplicationController
# ...
def create
#hikingtrail = Hikingtrail.new(params[:hikingtrail])
#hikingtrail.user = current_user
if #hikingtrail.save
# ...
else
# ...
end
end
end
Hope this helps :)

Nested Form has_many

I am not sure how to proper create a rails form with nested form. I have followed many tutorial but becoming more confused has in what should it be, singular plurials, controller... Here my models
model/event.rb
attr_accessible :description :title, :tag_ids, :locations_attributes
has_many :location
accepts_nested_attributes_for :location, :allow_destroy => true
model/location.rb
attr_accessible :address, :customer_id, :event_id, :latitude, :longitude
belongs_to :customer
belongs_to :event
controller.rb
def new
#event = Event.new
...
def create
#event = Event.new(params[:event])
...
view form.html.erb
<%= form_for(#event) do |f| %>
<%= f.fields_for :locations do |e| %>
<%= e.text_field :longitude %>
<%= e.text_field :latitude %>
<% end %>
...
<% end %>
error
Can't mass-assign protected attributes: locations
params send
"locations"=>{"longitude"=>"45.6666",
"latitude"=>"47.44444665"},
Either my relationship are wrong because fields_for doesn't support it, either my controller is not proper, or either rails is just not a great language, or i don't understand it anymore.
You.re nearly there...
event.rb - locations NOT location
attr_accessible :description :title, :tag_ids, :locations_attributes
has_many :locations
accepts_nested_attributes_for :locations, :allow_destroy => true
Should do it I think
edit
And as Valery Kvon says, you need to add
#event.locations.build
to your controller
Edward's answer +
def new
#event = Event.new
#event.locations.build
end

Insert more than one item from a belongs_to association using nested forms

in my Rails way, I have just found another question to the commmunity.
I have the following project: I have a calendar which render me the events that any client have dealed with my company. If I want to insert a new event with only one client, I have no problem, but if I want to insert a new event with more than one client, I have a problem.
But it's been impossible to insert more than one client at the same time. I know that with this configuration, Rails only accepts one client for every instance of event, and one solution could be change the association model between Event and Client, but it makes no sense for me (event has_many clients and client belongs_to events... sounds weird). So, this post it's related to compile options from the community.
This is my code (I'm using the nested_form gem by Ryan Bates [github.com/ryanb/nested_form.git]):
UPDATE: By the moment, I introduce a new model Group, in this way:
models/group.rb
class Group < ActiveRecord::Base
has_many :clients
has_many :events
accepts_nested_attributes_for :clients
accepts_nested_attributes_for :events
attr_accessible :events_attributes, :clients_attributes
end
models/client.rb
class Client < ActiveRecord::Base
has_many :events
belongs_to :group
accepts_nested_attributes_for :events
accepts_nested_attributes_for :group, :update_only => true
attr_accessible :name, :surname, :email, :group_attributes, :events_attributes
end
models/event.rb
class Event < ActiveRecord::Base
belongs_to :group
accepts_nested_attributes_for :group, :update_only => true
attr_accessible :title, :group_id, :starts_at, :ends_at, :group_attributes
end
views/events/_form.html.erb
<%= simple_nested_form_for #event do |f| %>
<%= f.input :title %>
<%= f.fields_for :group do |group_form| %>
<%= group_form.fields_for :clients do |client_form| %>
<%= client_form.input :name %>
<%= client_form.input :surname %>
<%= client_form.input :email, :as => :email %>
<%= client_form.link_to_remove "Remove this client" %>
<% end %>
<%= group_form.link_to_add "Add another client", :clients %>
<% end %>
<%= f.input :starts_at, :as => :datetime %>
<%= f.input :ends_at, :as => :datetime %>
<%= f.button :submit %>
<% end %>
But know, my problem is that, when I create an event for one group, this group is successfully create when I insert ONLY ONE client. When I try to insert two or more clients I get the next:
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: new_1332430522879):
app/controllers/events_controller.rb:44:in `new'
app/controllers/events_controller.rb:44:in `create'
Ah! And I forget to comment before (but I think that is not relevant for that), that I'm using Ruby 1.9.3-p125 and Rails 3.2.2
Any ideas?
Thanks in advance...
Foncho

Nested Attributes when Viewing Multiple Models (not a form)

I am having trouble rendering a model's attributes in foreign model's view. I think it is a nested attributes problem because f.bike works but f.bike.biketype gives an undefined method error. Below is my error and code. Any help would be great. Thanks!
Error from Browser:
NoMethodError in Carts#show
Showing /Users/willdennis/rails_projects/spinlister/app/views/carts/show.html.erb where line #4 raised:
undefined method `biketype' for nil:NilClass
Extracted source (around line #4):
1: <h2>Your Cart</h2>
2: <ul>
3: <% #cart.line_items.each do |f| %>
4: <li><%= f.bike.biketype %></li>
5: <% end %>
6: </ul>
views/carts/show.html.erb
<h2>Your Cart</h2>
<ul>
<% #cart.line_items.each do |f| %>
<li><%= f.bike.biketype %></li>
<% end %>
</ul>
cart.rb
class Cart < ActiveRecord::Base
has_many :line_items, :dependent => :destroy
belongs_to :user
accepts_nested_attributes_for :line_items
attr_accessible :bike_id, :name, :description, :size, :biketype, :price, :photo, :id, :address, :city, :state, :zip, :latitude, :longitude, :neighborhood
end
line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :bike
belongs_to :cart
accepts_nested_attributes_for :bike, :cart
attr_accessible :name, :description, :size, :biketype, :price, :photo, :id, :address, :city, :state, :zip, :latitude, :longitude, :neighborhood
end
bike.rb
class Bike < ActiveRecord::Base
has_many :line_items
attr_accessible :name, :description, :size, :biketype, :price, :photo, :id, :address, :city, :state, :zip, :latitude, :longitude, :neighborhood
end
carts_controller.rb
def show
#cart = Cart.find(params[:id])
end
Your error is telling you that the object f.bike is of class nil. You would have been expecting it to be an instance of class Bike. Obviously you have a line item in your view that doesn't have a bike record attached to it.
To take care of the error so your view will display just add a check for blank?
li><%= f.bike.biketype unless f.bike.blank? || f.bike.biketype.blank? %></li>
As to why you have a line item with no bike? Well that's an entirely different question and there is not enough info here to answer that.
UPDATE Based on comments below
Your button_to looks a little wrong. Try
<%= button_to "Rent this Bicycle!", {line_items_path(:bike_id => #bike)}, {:id => "rentthisbike"} %>
Using the curly braces ensures that Rails knows the second param is a css style not a param to be passed into the controllers action
To check if your bike id is getting into the controller then check the params that are actually getting into the controller action that add the bike to the line item. You will be able to find this in your development.log file, find the post request for the action and one of the first lines in that action will list all the params. If you see the bike_id in that list then either one of 2 possible situations is occurring.
1) You are not accessing the params hash properly to get the bike id from it
or
2) You are not setting the bike ID on the line item before saving the record.
You should be able to access the id using params[:bike_id]
If you don't see the bike id then you need to look again at the button_to code to see why it's not passing the bike ID
End of update
Hope that helps

Resources