HAML and mistake in form_for - ruby-on-rails

I'm learning HAML and I have a problem with from_for
%b New Advert!
- form_for #car, :url => { :action => "create" } do |f|
= f.text_field :body
= f.submit t('advert.form.save')
My Controller advert_controller
class AdvertController < ApplicationController
def new
#car = Car.new
end
def create
#car = Car.new(params[:car])
end
end
And my model car.rb
class Car < ActiveRecord::Base
attr_accessible :title, :body
end
But I have a mistake:
undefined method `body' for #
NoMethodError in Advert#new
Showing /my_project/app/views/advert/new.html.haml where line #4 raised
UPD form_for with '=' doesn't work
= form_for #car, :url => { :action => "create" } do |f|
= f.text_field :body
= f.submit t('advert.form.save')

I can see two errors here :
first you should use = instead of - for form_form, indeed = will output the result whereas - won't.
As form_for returns HTML for the form, you want it to be written on the page ;)
As for the cause of your error, well I'm not entirely sure, but it seems that your Car model doeesn't have a body field and so it does not have a body method

Related

Undefined method error on User child object Rails 4

I have an object(Transaction) that belongs_to User and User has_many transactions. When I try and create this object in my rails form I get the following error:
undefined method `transaction_kind' for nil:NilClass
app/models/transaction.rb:10:in `create_transaction'
app/controllers/transactions_controller.rb:17:in `create'
The params hash being passed through my console after I submit the form looks like:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XXXXX", "transaction"=>{"transaction_kind"=>"Deposit", "user_id"=>"113", "credit"=>"99"}, "commit"=>"Submit Request", "lender_id"=>"113"}
Transaction.rb looks like this:
class Transaction < ActiveRecord::Base
belongs_to :user
after_save :create_transaction
attr_accessible :transaction_kind, :user_id, :credit, :debit, :created_at
def create_transaction
client = Restforce.new
credit = '012c00000004k5A'
debit = '012c00000004k55'
if #transaction.transaction_kind == "Deposit"
client.create!('Transaction__c', Account__c: self.salesforce_id, RecordTypeId: credit, Debit_Amount__c: self.debit, Credit_Amount__c: self.credit, Recorded_On__c: self.created_at, Status__c: 'New Transaction', Type: 'Deposit', Transaction_Type__c: self.transaction_kind)
else
client.create!('Transaction__c', Account__c: self.salesforce_id, RecordTypeId: debit, Debit_Amount__c: self.debit, Credit_Amount__c: self.credit, Recorded_On__c: self.created_at, Status__c: 'New Transaction', Type: 'Withdrawal', Transaction_Type__c: self.transaction_kind)
end
end
end
new.html.erb has the following form code:
<%= form_for [#user, #transaction], url: lender_transaction_path(#user) do |f| %>
<%= f.hidden_field :transaction_kind, :value => "Deposit" %>
<%= f.hidden_field :user_id, :value => #user.id %>
<%= f.label :credit, :class => "required" %>
<%= f.text_field :credit, :autofocus => :true, :class => "form-control margin-bottom-20 required"%>
<%= f.submit 'Submit Request', :class => "btn-u btn-u-primary" %>
<% end %>
transactions_controller.rb
class TransactionsController < ApplicationController
before_filter :authenticate_user!
def new
#user = current_user
#transaction = Transaction.new
if #user.activated?
client = Restforce.new
#account = client.find('Account', #user.salesforce_id, 'Account_Id')
transaction_query = "select from where Account__c ='%s' AND " % #account.Id.to_s
#transactions = client.query(transaction_query)
end
end
def create
#user = current_user
#transaction = Transaction.create(transaction_params)
if #transaction.save
redirect_to new_lender_transaction_path(#user)
end
end
private
def transaction_params
params.require(:transaction).permit(:transaction_kind, :credit, :debit, :created_at)
end
end
Any help with this issue would be great. Or any ideas on how to debug this further. Thanks!
You can't pass an instance variable from controller to model, so the Transaction model doesn't know what #transaction is and thus supposes it is as a nil
I would change the code into this:
if self.transaction_kind == "Deposit"
The self will make it work. If it is not, try using attr_accessor :transaction_kind or simply put if transaction_kind == "Deposit"
Also, I believe it would be better if you refactor the client.create! into:
Restforce.create!(...)
which will save you from writing another client = Restforce.new line.

Rails 3: save method wont work

I'm building my first Rails Application and until now everything went fine but then I found the following scenario: One Presentation is supposed to have N Iterations. I'm NOT using REST. So, I was trying to make a simple form to create iterations.
These are the models:
class Presentation < ActiveRecord::Base
has_many :iterations
end
class Iteration < ActiveRecord::Base
belongs_to :presentation
attr_accessible :presentation_id, :description, :delivery_date, :file
validates :presentation_id, :presence => {:message => 'is required.'}
end
These are the actions in the controller:
#Shows Form
def add
#iteration = Iteration.new
#presentation = Presentation.find(params[:id])
end
#Saves Form
def save
#iteration = Iteration.new(params[:iteration])
#iteration.delivery_date = Time.now
if #iteration.save
flash[:notice] = "Saved succesfully!"
else
flash[:error] = "Changes were not saved."
end
redirect_to root_url
end
These would be the view in HAML:
= form_for #iteration, :url => { :action => "save", :method => "post" }, :html => { :multipart => true } do |f|
- if #iteration.errors.any?
There were some errors:
.notice-text.fg-color-white
%ul.notice
- for message in #iteration.errors.full_messages
%li= message
%br
.field
= f.label :description, "Description"
= f.text_area :description, :class=>"form-text-area", :rows=>5
.field
= f.label :file, "Upload File"
= f.file_field :file
.field
= hidden_field_tag :presentation_id, #presentation.id
%br
= f.submit "Save"
The problem is, save method wont save, but #iteration.errors.count's value on the view is 0.
I used then save! instead as I read in another post, that way it throw the following error:
Validation failed: Presentation is required.
I can't figure out what I'm doing wrong. Please notice that in the view I used to have "f.hidden_field" instead of "hidden_field_tag" but I changed it for some other reasons, however I was getting the same error before that.
Your HAML,
hidden_field_tag :presentation_id
needs to be,
f.hidden_field :presentation_id, :value => #presentation.id
Looking at the your model definition you can have,
Nested resource: Refer to Controller path for nested resource - undefined method `<controller>_path'
Use Virtual attributes: Extremely useful railcasts by Ryan on this -> http://railscasts.com/episodes/16-virtual-attributes-revised
Save the presentation id in session: (This is not a clean very clean method)
On your controller, you will need to instantiate iteration on presentation so that presentation id is correctly populated.

What's causing this "undefined method `model_name' for NilClass:Class" error?

I have...
rake routes:
edit_report_question
GET
/reports/:report_id/questions/:id/edit(.:format)
questions#edit
questions_controller.rb:
def edit
#report = Report.find(params[:report_id])
#questions = #report.questions.find(params[:id])
end
report.rb:
has_many :questions
question.rb:
belongs_to :report
edit.html.haml:
.textbox
= render "shared/notice"
%h1 Edit Question
= render "form"
= render "actions"
_form.html.haml:
= simple_form_for [#report, #question] do |f|
= f.error_notification
= f.association :report
= f.input :description
= f.input :blueprint_name, :label => "Blueprint Name"
= f.input :blueprint_url, :label => "Blueprint URL"
= f.association :element, :label => "Website Element"
= f.association :standard
- if params[:action]=~ /edit/
= f.association :fields, :as => :select
= f.button :submit, :id => 'submit_question'
params:
{"action"=>"edit", "controller"=>"questions", "report_id"=>"1", "id"=>"1"}
Why then am I getting a "undefined method `model_name' for NilClass:Class" error?
Note: at present each report has many questions, but eventually I want reports to have many and belong to many questions.
You have not defined '#question' anywhere in the controller, i think your controller action should be like
def edit
#report = Report.find(params[:report_id])
#question = #report.questions.find(params[:id]) # replacing #questions with #question
end
You are getting nil class error because #questions is an instance variable and don't have anything in it. Plus please try to dig out before posting. Thanks
the line that's causing the error is this line
simple_form_for [#report, #question]
since in the controller, you dont have #question variable, Rails can't infer the path of the form. I think #questions there should be #question
#questions = #report.questions.find(params[:id])

Rails 3.1: Polymorphic Association #commentable - how to do it right?

I am having troubles with a polymorphic association in Rails. I have an application where it should be possible to comment on different models, such as Posts, Images, Projects
Right now I just have Posts to comment on. On the start page there is an index view of the latest Posts and each Post has a small Comment form underneath to comment on via Ajax, very much like Facebook.
My models look like this:
class Post < ActiveRecord::Base
belongs_to :post_category
belongs_to :user
has_many :comments, :as => :commentable
validates_presence_of :user_id
validates_presence_of :post_category_id
validates_presence_of :title
validates_presence_of :body
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
end
Now in my Comments controller I added the following method (I think I took it from railscasts or something), which I assume tries to find out the #commentable dynamically when creating an comment.
But this always returns the error undefined methodcomments' for nil:NilClass`
# find commentable (parent) item
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value) unless name == 'user_id'
end
end
nil
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
redirect_to #comment, :notice => 'Comment was successfully created.'
redirect_to :id => nil
else
render :action => "new"
end
end
The two things I tried in my partial were:
leaving the commentable info out of the form
= form_for [#commentable, Comment.new], :remote => true do |f|
#new_comment.add_comment
= f.hidden_field :user_id, :value => current_user.id
= f.text_field :content, :size => 55, :value => 'leave a comment...', :class => 'comment_form'
= f.submit "send"
and 2. passing the commentable_id and commentable_type
= form_for [#commentable, Comment.new], :remote => true do |f|
#new_comment.add_comment
= f.hidden_field :user_id, :value => current_user.id
= f.hidden_field :commentable_id, :value => post_id
= f.hidden_field :commentable_type, :value => 'Post'
= f.text_field :content, :size => 55, :value => 'leave a comment...', :onfocus => 'this.select()', :class => 'comment_form'
= f.submit "send"
both without luck. Any help would be highly appreciated.
the whole comments controller code is in this gist: https://gist.github.com/1334286
It seems like the commentable is not assigned correctly in the comments controller. This could have multiple reasons. Here is a setup that should work for you:
In the Posts controller, e.g. action "show":
#post = Post.find(params[:id])
In the posts/show view comments form:
= form_for [#post, #post.comments.new], :remote => true do |f|
You should be able to use your comments controller as it - but you should change the render to e.g. a redirect_to :back in the create action since the comments controller will most probably not have a "new" view on its own (it is dependent from the commentable)
Also, make sure that you have nested routes for all resources that can act as a commentable, like so:
resources :posts do
resources :comments do
end
resources :comments do
resources :comments # subomments
end
UPDATED to reflect information in the comments
Don't use #commentable in the post show view, since it's only defined in the comments controller.
Do this instead:
_comment.html.erb: (the comment partial in the post show view)
<%= form_for ([comments, #vote]), remote: true do |f| %>
posts/posts_controller.rb:
<%= form_for ([#post, #vote]), remote: true do |f| %>

In Rails, how do you call a specific method in a controller from a form in a view?

new to rails so bear with me. What I would like to do, is I have a list of messages on the screen. I want the message to be marked as 'closed' which means it just fills in a completeDate.
I have a model:
class Message < ActiveRecord::Base
attr_accessible :topic, :body, :completeDate, :created_at
belongs_to :account
belongs_to :user
has_many :message_followups
end
I have a controller:
class MessagesController < ApplicationController
def close
#message = Message.find(params[:messageId])
#message.completeDate = Date.today
if #message.save
redirect_to myHomeMessages_path, :flash => { :success => "Your message was closed." }
else
redirect_to myHomeMessages_path, :flash => { :error => "Error closing message." }
end
end
end
I have a view:
<%= form_for (???) do |f| %>
Are you sure you wish to close this message?<br>
<%= hidden_field_tag 'messageId', message.id.to_s %>
<%= submit_tag "Close Message" %>
<% end %>
I'm having a problem figuring out how to get the form_for or a form_tag to call the specific method 'close' in the messages controller. Any help would be greatly appreciated, thanks.
Matt
A very important hint, you should not use camel case for variable names on Ruby, variable sand methods should use underscore as separators, if you're coming from another language like Java, try to avoid using the same naming patterns you used in there. Camel case in ruby is only for class and module names.
I am guessing you're using Ruby on Rails 3, as you haven't said what you're using. First, you need a route for that, it would look like this on your routes.rb file:
resources :messages do
member do
post 'close'
end
end
A little change to your controller
def close
#message = Message.find(params[:id]) #you don't need to use the hidden field here
#message.completeDate = Date.today
if #message.save
redirect_to myHomeMessages_path, :flash => { :success => "Your message was closed." }
else
redirect_to myHomeMessages_path, :flash => { :error => "Error closing message." }
end
end
And your form is going to look like this:
<%= form_for( #message, :url => close_message_path( #message ), :html => { :method => :post } ) do |f| %>
Are you sure you wish to close this message?<br>
<%= f.submit "Close Message" %>
<% end %>
This form is going to be posted to "/messages/ID_HERE/close" and Rails is going to set the "ID_HERE" value as the "id" parameter on your request.
You can see the full documentation about form_for here.
Something like this should square things away for you:
<%= form_for #message, :url => { :action => "close" }, :html => { :method => :put } do |f| %>
What this does is specify that you are performing an HTTP PUT method to the close method in the messages controller. For more information about the form_for helper method read here
Do you have an update method in your controller, if not you can just do this:
<%= form_for( #message ) do |f|
<p>Are you sure you wish to close this message?</p>
<%= hidden_field_tag :close %>
<%= f.submit "Close Message" %>
<% end %>
Then in your controller:
class MessagesController < ApplicationController
def update
#message = Message.find(params[:id])
#message.completeDate = Date.today if params.has_key?(:close)
if #message.save
redirect_to myHomeMessages_path,
:flash => { :success => "Your message was closed." }
else
redirect_to myHomeMessages_path,
:flash => { :error => "Error closing message." }
end
end
end

Resources