Rails nested form, attributes not getting passed - ruby-on-rails

So I have a Conversation model, which has_many messages. I'm trying to create a new message when I create a conversation. Here's my ConversationsController:
class ConversationsController < ApplicationController
before_filter :authenticate_user!
def new
recipient = User.find(params[:user])
#conversation = Conversation.new(from: current_user, to: recipient)
#conversation.messages.build(from: current_user, to: recipient)
end
def create
#conversation = Conversation.create(params[:conversation])
redirect_to #conversation
end
end
And here's my form (conversations/new.html.erb):
<%= form_for #conversation do |f| %>
<%= f.fields_for :messages do |g| %>
<%= g.label :subject %>
<%= g.text_field :subject %>
<%= g.label :content %>
<%= g.text_field :content %>
<% end %>
<%= f.submit "Send" %>
<% end %>
The problem: when I submit the form, the conversation's message gets saved, but the to and from fields that I specified as parameters in build are not saved (they are nil). However, the subject and content fields filled out in this form are saved just fine.
I've done a little bit of digging... if I do a puts on #conversation.messages in the new action, or in the new.html.erb, the message seems to have to and from. It's only when the message reaches the create action do those fields disappear.

UPDATED:
class ConversationsController < ApplicationController
before_filter :authenticate_user!
def new
recipient = User.find(params[:user])
#conversation = Conversation.new(to: recipient)
#conversation.messages.build
end
def create
#conversation = current_user.conversations.build(params[:conversation])
# Set all the attributes for conversation and messages which
# should not be left up to the user.
#conversation.to = current_user
#conversation.messages.each do |message|
message.to = #conversation.to
message.from = #conversation.from
end
redirect_to #conversation
end
end
<%= form_for #conversation do |f| %>
<%= f.hidden_field :recipient %>
<%= f.fields_for :messages do |g| %>
<%= g.label :subject %>
<%= g.text_field :subject %>
<%= g.label :content %>
<%= g.text_field :content %>
<% end %>
<%= f.submit "Send" %>
<% end %>
You may still want to validate the recipient in your Conversation model.

Related

Ruby on Rails: Populate dropdown with two fields of database record

In my database I have a Users table that looks something like:
User_ID Firstname Surname Company
1 Steve Jobs Apple
2 Bill Gates Microsoft
What I am trying to do is make a drop down menu in a form that would allow a user to choose from selecting their name or their company, e.g. when Steve Jobs is logged in he can either select "Steve" or "Apple" in the drop down menu.
What I have tried so far is the following:
<%= f.select :from_name, [session[:user_id],session[:user_id]] %>
Which obviously didn't work because it only returns the user id of the logged in user.
<%= f.select :from_name, [#user.firstname,#user.company] %>
Which gave me the error undefined methodfirstname for nil:NilClass`
My Users controller is as follows:
class UsersController < ApplicationController
before_filter :check_authorization, :except => [:show, :new, :create, :search ]
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
#user.role = "customer"
if #user.save
session[:user_id] = #user.id
# Save a copy of the email address entered by the user into the Accounts table
#account = Account.create(email: params[:user][:primaryemailaddress], user_id: session[:user_id])
redirect_to root_path
else
render 'new'
end
end
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to #user
else
render 'edit'
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_path
end
private
def user_params
params.require(:user).permit(:title, :firstname, :surname, :housenumber, :street, :city, :postcode, :company, :primaryemailaddress, :password)
end
end
And my _form.html.erb is:
<%= form_for(#email) do |f| %>
<% if #email.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#email.errors.count, "error") %> prohibited this email from being saved:</h2>
<ul>
<% #email.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :from_name %><br>
<%= f.select :from_name, [current_user.firstname, current_user.company] %>
</p>
<p>
<%= f.label :From_Email_Address %><br>
<%= f.collection_select :account_id, Account.where(user_id: session[:user_id]),
:id,:email %>
</p>
<p>
<%= f.label :to %><br>
<%= f.text_field :to %>
</p>
<p>
<%= f.label :cc %><br>
<%= f.text_field :cc %>
</p>
<p>
<%= f.label :bcc %><br>
<%= f.text_field :bcc %>
</p>
<p>
<%= f.label :subject %><br>
<%= f.text_field :subject %>
</p>
<p>
<%= f.label :message %><br>
<%= f.text_field :message %>
</p>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I'm not too sure how to solve this issue, can someone please help.
#BenSmith I guess you are accessing EmailsController. And on that controller's new or edit method there is no #user variable.
In your edit and new method add
#user = User.find(session[:user_id])
undefined method firstname for nil:NilClass
Seems like some how #user is nil
create a helper and check for presence of #user
<%= f.select :from_name, dropdown_values %>
application_helper.rb
def dropdown_values
if #user.present?
[#user.firstname, #user.company]
else
['default', 'values']
end
end
<p>
<%= f.label :from_name %><br>
<%= f.select :from_name, [current_user.firstname, current_user.company] if #user.present?%>
</p>
because User.new time create blank object doesn't find username.i hope its will be help you.

undefined method `reviews' for nil:NilClass

I'm trying to create a reviews model for company pages. For this I have:
Models
user.rb
has_many :reviews
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :reviews
end
My reviews controller is:
def create
#company = Company.find_by_slug(params[:id])
#review = #company.reviews.create(params[:review])
#review.save
redirect_to company_path(#company)
end
and I have this code in the company show page:
<% #company.reviews.each do |review| %>
<p>
<strong>Title:</strong>
<%= review.title %>
</p>
<p>
<strong>Avantage:</strong>
<%= review.avantage %>
</p>
<p>
<strong>Inconvenient:</strong>
<%= review.inconvenient %>
</p>
<% end %>
</br>
<%= form_for([#company, #company.reviews.build]) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :avantage %><br>
<%= f.text_area :avantage %>
</div>
<div class="field">
<%= f.label :inconvenient %><br>
<%= f.text_area :inconvenient %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
However, when I go to a specific company page and try to create a review for this company I'm getting this error message undefined method reviewsfor nil:NilClass
Instead of #company = Company.find_by_slug(params[:id]) use this code #company = Company.friendly.find(params[:company_id])
There are a couple of things you may find useful:
If you're using Rails 4, you may encounter a further problem. In the third line of your create method, you are using unsecure params directly in a .create call. Check out the Rails Guide page on "strong params".
If you implement strong parameters as mentioned above, you should probably deliberately omit the company_id field from the list of permitted params.
Assuming your users are allowed to write a review for any company in your system, it might be simpler for you to embed the company_id as a hidden field in your form. This would allow you to also simplify the controller method. For example:
# _form.html.erb
<%= form_for(#review) do |f| %>
<%= f.hidden_field :company_id, value: #company.id %>
...bla bla bla
<% end %>
Then, in your reviews_controller...
# reviews_controller.rb
def create
#review = Review.new(approved_params)
if #review.save
flash[:success] = 'Review created!'
else
flash[:error] = "Review wasn't saved"
end
#company = #review.company
redirect_to #company
end
def approved_params
params.require(:review).permit(:title, :avantage, :inconvenient, :company_id)
end
In your companies_controller, you should add this to your show method
# companies_controller.rb
def show
#company = Company.find(params[:id]
# add this line below...
#review = Review.new
end
I hope this helps.

Ruby / ActionMailer / Saving mail

I am creating a customer support app where clients can create, view, edit and comment support tickets.
I have this portion of the app working fine, but I want to have the data they submit into the ticket form emailed to me.
I have a separate "contact us" form that emails the data to me perfectly, but I want to combine the two forms into one.
It should work like this: client creates ticket, ticket is saved into the database, a copy of the ticket is emailed to me.
I can't figure out how to make all of these actions happen from one form.
Here is my tickets controller:
class TicketsController < ApplicationController
def new
#ticket = Ticket.new
end
def create
#ticket = Ticket.new(ticket_params)
#ticket.save
redirect_to #ticket
end
def show
#ticket = Ticket.find(params[:id])
end
def index
#tickets = Ticket.all
end
def edit
#ticket = Ticket.find(params[:id])
end
def update
#ticket = Ticket.find(params[:id])
if #ticket.update(ticket_params)
redirect_to #ticket
else
render 'edit'
end
end
def destroy
#ticket = Ticket.find(params[:id])
#ticket.destroy
redirect_to tickets_path
end
private
def ticket_params
params.require(:ticket).permit(:name, :email, :phone, :help)
end
end
Here is my new ticket view:
<%= link_to "View an Existing Ticket", tickets_path, :class =>'btn btn-danger btn-sm'%>
<h1>New Ticket</h1>
<%= form_for :ticket, url: tickets_path do |f| %>
<p>
<%= f.label "Name:" %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label "Email:" %>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :"Phone #:" %>
<%= f.text_field :phone %>
</p>
<p>
<%= f.label :"How can we help?" %>
<p><%= f.text_area :help, :cols=> 38, :rows => 8 %></p>
</p>
<p>
<button type="submit" class="btn btn-danger btn-sm">Submit Ticket</button>
</p>
<% end %>
<p><%= button_to "Back", root_path, :class => "btn btn-danger btn-sm", :method => :get %></p>
Here is my email controller:
class ContactController < ApplicationController
def new
#message = Message.new
end
def create
#message = Message.new(params[:message])
if #message.valid?
NotificationsMailer.new_message(#message).deliver
redirect_to(root_path, :notice => "Message was successfully sent.")
else
flash.now.alert = "Please fill all fields."
render :new
end
end
end
Here is my email view:
<%= form_for #message, :url => contactcreate_path do |form| %>
<fieldset class="fields">
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :email %>
<%= form.text_field :email %>
</div>
<div class="field">
<%= form.label :subject %>
<%= form.text_field :subject %>
</div>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
</fieldset>
<fieldset class="actions">
<%= form.submit "Send" %>
</fieldset>
<% end %>
Ticket Model:
class Ticket < ActiveRecord::Base
after_create :send_new_ticket_to_email
private
def send_new_ticket_to_email
NotificationsMailer.send_new_ticket(self).deliver
end
end
Notifications Mailer:
class NotificationsMailer < ActionMailer::Base
def send_new_ticket(ticket)
#ticket = ticket
mail(:subject => "HelpDesk: #{message.subject}")
default :from => "HelpDeskApp#ascendstudioslive.com"
default :to => "Support#ascendstudioslive.com"
end
Let me know if there is anything else you would like to see. Basically, I want to have one form that saves a ticket to the database and then emails a copy of it out.
Thank you!
You can create an after_create callback in your Ticket model to e-mail the saved ticket to yourself.
class Ticket < ActiveRecord::Base
after_create :send_new_ticket_to_email
private
def send_new_ticket_to_email
UserMailer.send_new_ticket(self).deliver
end
end
and in your ActionMailer class:
class UserMailer < ActionMailer::Base
def send_new_ticket(ticket)
#ticket = ticket
/* here you configure the variables for your email */
mail(to: your#email.com, subject: 'New ticket...')
end
end
then you will be able to use the #ticket object in your mailer views whatever way you please.
Have you tried this? I don't know if it is going to work, but all the same:
#new_message = NotificationsMailer.new_message(#message)
save_to_db(#new_message) # custom method to write it into your db somehow
#new_message.deliver
Not really sure what a contact is versus a ticket, but, broadly, the way to do what you want is, in your create action:
def create
#message = Message.create(params[:message])) # create will save and validate the message
if #message.valid?
NotificationsMailer.new_message(#message).deliver # #message gets set to
# else...
end

Getting from controller to associated model

I can't get along with saving Students with one POST when i"m saving Project.
My Projects controller looks like:
class ProjectsController < ApplicationController
def index
#projects = Project.all
end
def new
#project = Project.new
3.times do
student = #project.students.build
end
end
def create
#project = Project.new(project_params)
#project.status = "Waiting"
# I'm not sure about these lines
#project.students.each do |student|
student = Student.new(params[:name])
end
#project.save!
redirect_to projects_path
end
private
def project_params
params.require(:project).permit(:name, :lecturer)
end
end
And a new_project view looks like:
<h1>Creating new project...</h1>
<%= form_for #project, url: projects_path do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :lecturer %>
<%= f.text_field :lecturer %>
</p>
<p>
<%= f.fields_for :students do |s| %>
<%= s.label :name %>
<%= s.text_field :name %>
<% end %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
And my question is how to save Project and Students (assigned to it) using one form?
First, your project_params method isn't allowing the students' names to be submitted. Try something like this:
def project_params
params.require(:project).permit(:name, :lecturer, students_attributes: [ :name ] )
end
Next, in your Project model you'll need the line
accepts_nested_attributes_for :students
(You might have put it there already - but if you didn't, you'll need to.)
Now that that's done, you shouldn't need these lines in your Project#create method:
#project.students.each do |student|
student = Student.new(params[:name])
end
Because your project can now accept nested attributes for students, they should be created automatically with the project when you save it.

params.require().permit does not work as expected

I have this controller
class PeopleController < ApplicationController
def new
#person = Person.new
#person.phones.new
end
# this is the action that gets called by the form
def create
render text: person_params.inspect
# #person = Person.new(person_params)
# #person.save
# redirect_to people_path
end
def index
#person = Person.all
end
private
def person_params
params.require(:person).permit(:name, phones_attributes: [ :id, :phone_number ])
end
end
and this view
<%= form_for :person, url: people_path do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :phones do |f_phone| %>
<div class="field">
<p>
<%= f_phone.label :phone_number %><br />
<%= f_phone.text_field :phone_number %>
</p>
</div>
<% end %>
<p>
<%= f.submit %>
</p>
<% end %>
When I fill out both form fields and hit "Save Person" I only get {"name"=>"foo"} - the phone number seems to vanish.
However, when I change phones_attributes to phones I get {"name"=>"foo", "phones"=>{"phone_number"=>"123"}} (this would however cause problems with the create function.
What's wrong here?
Please note that this question is strongly related to that one: accepts_nested_attributes_for: What am I doing wrong as well as to this posting: https://groups.google.com/forum/#!topic/rubyonrails-talk/4RF_CFChua0
You don't have #phones defined in the controller:
def new
#person = Person.new
#phones = #person.phones.new
end
Finally found the problem. In the view there should be
<%= form_for #person, url: people_path do |f| %>
Instead of
<%= form_for :person, url: people_path do |f| %>
#phron said that already here:
accepts_nested_attributes_for: What am I doing wrong

Resources