Rails: Problem with routes and special Action - ruby-on-rails

Sorry for this question but I can't find my error!
In my Project I have my model called "team".
A User can create a "team" or a "contest". The difference between this both is, that contest requires more data than a normal team.
So I created the columns in my team table.
Well... I also created a new view called create_contest.html.erb :
<h1>New team content</h1>
<% form_for #team, :url => { :action => 'create_content' } do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>
<%= f.label :url %><br />
<%= f.text_fiels :url %>
</p>
<p>
<%= f.label :contact_name %><br />
<%= f.text_fiels :contact_name %>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
In my teams_controller, I created following functions:
def new_contest
end
def create_contest
if #can_create
#team = Team.new(params[:team])
#team.user_id = current_user.id
respond_to do |format|
if #team.save
format.html { redirect_to(#team, :notice => 'Contest was successfully created.') }
format.xml { render :xml => #team, :status => :created, :location => #team }
else
format.html { render :action => "new" }
format.xml { render :xml => #team.errors, :status => :unprocessable_entity }
end
end
else
redirect_back_or_default('/')
end
end
Now, I want on my teams/new.html.erb a link to "new_contest.html.erb".
So I did:
<%= link_to 'click here for new contest!', new_contest_team_path %>
When I go to the /teams/new.html.erb page, I get following error:
undefined local variable or method `new_contest_team_path' for #<ActionView::Base:0x16fc4f7>
So I changed in my routes.rb, map.resources :teams to map.resources :teams, :member=>{:new_contest => :get}
Now I get following error: new_contest_team_url failed to generate from {:controller=>"teams", :action=>"new_contest"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["teams", :id, "new_contest"] - are they all satisfied?
I don't think adding :member => {...} is the right way doing this. So, can you tell me what to do? I want to have an URL like /teams/new-contest or something.
My next question: what to do (after fixing the first problem), to validate presentence of all fields for new_contest.html.erb? In my normal new.html.erb, a user does not need all the data. But in new_contest.html.erb he does. Is there a way to make a validates_presence_of only for one action (in this case new_contest)?
UPDATE:
Now, I removed my :member part from my routes.rb and wrote:
map.new_contest '/teams/contest/new', :controller => 'teams', :action => 'new_contest'
Now, clicking on my link, it redirects me to /teams/contest/new - like I wanted - but I get another error called:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
I think this error is cause of #team at <% form_for #team, :url => { :action => 'create_content_team' } do |f| %>
What to do for solving this error?

I'm not sure about how your models work, but in my code I've always written;
#team.user_id = #current_user.id
instead of
#team.user_id = current_user.id
That would mean the id wasn't being passed to the controller giving you the error, wouldn't it?

Okay, I found my errors.
For the record:
First of all, I forgot to write the code inside my def new_contest. Here it is:
def new_contest
if #can_create
#team = Team.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #team }
end
else
redirect_back_or_default('/')
end
end
There were several typos, too, in my .erb file like text_fiels instead of text_field or create_content instead of create_contest.
current_user is working fine for me.

Related

Keep params after render Ruby on Rails

I have a Project that belongs to User. In my user view I have a link to add a new project, with the parameter for the user I want to add the project to.
<%= link_to 'Add new project', :controller => "project", :action => "new", :id => #user %>
Url: /projects/new?id=62
Adding a project to a user works. The problem is when the validation fails while adding a new project and I do a render.
def create
#project = Project.new(params[:project])
if #project.save
redirect_to :action => "show", :id => #project.id
else
render :action => "new"
end
end
view:
<%= form_for #project do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.hidden_field :user_id , :value => params[:id] %>
<%= f.submit "Create project" %>
<% end %>
routes
resources :users do
resources :projects
end
How can I keep the parameter for the user after the render? Or is there some better way to do this? Been looking at a lot of similar questions but can't get it to work.
try
render :action => "new", :id => #project.id
if its not works for you, then try alternate way to pass the parameter to your render action.
This can also help you->
Rails 3 Render => New with Parameter
You shouldn't use params[:id] to assign value to this form field. Instead, add this to your #new action in controller:
def new
#project = Project.new(user_id: params[:id])
end
and then just write this in your form:
<%= f.hidden_field :user_id %>
Because #project was defined in your #new and #create actions and because it already contains a Project instance with a user_id assigned to it, the value would automatically be added to this field.

Rails : change user preference form

I have an User model who has_one :preference, but I would like to join the form to update the user and the form to update his preference, so in the user's form, I added :
<% if !#user.new_record? %>
<div class="field">
<%= label_tag 'user_preference_quote_type', 'Type de citations' %><br />
<%= text_field_tag 'user_preference_quote_type', #user.preference.quote_type %>
</div>
<div class="field">
<%= label_tag 'user_preference_locale', 'Langage' %><br />
<%= text_field_tag 'user_preference_locale', #user.preference.locale %>
</div>
<% end %>
And in my controller :
def update
#user = User.find(params[:id])
#user.preference.quote_type = params[:user_preference_quote_type]
#user.preference.locale = params[:user_preference_locale]
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to(#user, :notice => t('c.users.update')) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
But the preferences would not change, how can I do it ? And is there is better way to do it ?
This is not a good way of doing that. You should use fields_for. It will make your form cleaner. By the way, what you're doing in the controller is not working because you use update_attributes to update your model that makes your assigments useless. Using the above mentioned fields_for will help you to clean the controller too. But be careful because you surely will need accepts_nested_attributes_for in your model.
Check out nested_attributes: http://apidock.com/rails/v3.1.0/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for

How to customize a form/POST in Rails?

Hey guys, this has been plaguing me all week long. I am new to Rails, so please be gentle :)
My root problem is I'm trying to write a form_for Post that will use autocompletion on an input to tie the post to a Client. The database is looking for a client_id, not a text name.
So I have tried a custom validation that will lookup the text value and replace it with an id.
My Post.rb file has this:
class Post < ActiveRecord::Base
belongs_to :client
attr_accessor :client_name
attr_accessible :client_name
before_validation_on_create :validate_client
def validate_client
self.client_id = 1 # just a test
end
def client_exists(passed_name)
return Client.where(:full_name => passed_name).first.blank?
end
end
But when I do this, none of the form variables get passed. The database gets all blank entries except for the client_id. How can I accomplish this? Why aren't my form variables being passed in? Many thanks in advance.
Edit 1: added create definition from posts_controller.rb
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html {
redirect_to(posts_url) # redirect_to(#post, :notice => 'Post was successfully created.')
}
format.xml { render :xml => #post, :status => :created, :location => #post }
format.js
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
Edit 2: Thanks to #apneadiving, I changed the attr_accesible to include the other attributes, and that passes the POST entries into the db.
attr_accessible :client_id, :time, :content, :client_name
But when I change the validate_client function to search for the client_id,
def validate_client
passed_name = self.client_name
if client_exists(passed_name)
c = Client.where(:full_name => passed_name).first
self.client_id = c.id
else
errors.add_to_base "Error"
end
end
It always gives me this error:
Called id for nil, which would
mistakenly be 4 -- if you really
wanted the id of nil, use object_id
Edit 3: Here's my post form. I can't get the value of :client_name properly.
<%= form_for(#post) do |f| %>
<%= render 'common/error_messages', :object => f.object %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content, :size => "50x6" %>
</div>
<div class="field">
<div class="sub-field">
<%= f.label :client_name %><br />
<%= f.text_field :client_name, :size => "26" %>
</div>
<div class="sub-field">
<%= f.label :date %><br />
<%= f.text_field(:time, :class => 'date', :size => "10", :value => Date.today.strftime('%m/%d/%Y')) %>
</div>
<div class="sub-field">
<%= f.label :time %><br />
<%= f.time_select :time %>
</div>
</div>
<div class="actions clear">
<%= f.submit %>
</div>
<% end %>
Edit 4: The solution. I was struggling to get the :client_name due to my text being too far tabbed in (I was originally privatizing the function and then took the word "private" out). A modified version of #apneadiving's answer solved it for me!
class Post < ActiveRecord::Base
belongs_to :client
attr_accessor :client_name
validate :validate_client
def validate_client
passed_name = self.client_name
unless client = Client.find_by_full_name(passed_name).blank?
self.client_id = Client.find_by_full_name(passed_name).id
else
errors.add(:client_name, "'#{passed_name}' cannot be found.")
end
end
end
Beware of your attr_acessible:
if you set one, you have to set all the variables that can be set through params. Otherwise they are protected against mass assignment
EDIT 1:
seems c.id is nil which means your client_exists function doesn't work as expected. Try the following (not tested):
def validate_client
unless client = Client.find_by_full_name(client_name).nil?
client_id = client.id
else
errors.add_to_base "Error"
end
end
Your client_exists code is wrong, it returns true if it doesn't exist.
Also, since your client_exists and the validation reuse the same query i would rewrite that a bit.
def validate_client
passed_name = self.client_name
existing_client = Client.where(:full_name => passed_name).first
if existing_client
self.client_id = existing_client.id
else
errors.add_to_base "Error"
end
end

Routing error when trying to use same view for update and create flows (Rails 3)

My overall use case:
I have a Listing model that has many images. The Listing detail page lists all the fields that can be updated inline (through ajax).
I want to be able to use the same view for both update listing and create new listing.
My listing controller looks as follows:
def detail
#listing = Listing.find(params[:id])
#image = Image.new #should this link somewhere else?
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #listing }
end
end
def create
# create a new listing and save it immediately. Assign it to guest, with a status of "draft"
#listing = Listing.new(:price_id => 1) # Default price id
# save it to db
# TODO add validation that it has to have a price ID, on record creation. So the view doesn't break.
#listing.save
#image = Image.new
# redirect_to "/listings/detail/#listing.id" #this didn't work
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #listing }
end
end
The PROBLEM
I'm using a partial that shows the same form for the create view and the detail view.
This works perfectly except for one thing:
When I pull up
http://0.0.0.0:3000/listings/detail/7, it works perfectly.
When I pull up
http://0.0.0.0:3000/listings/new, I get the following error:
Showing /Applications/MAMP/htdocs/rails_testing/feedbackd/app/views/listings/_edit_form.html.erb where line #100 raised:
No route matches {:action=>"show", :controller=>"images"}
Extracted source (around line #100):
97: <!-- Form for new images -->
98: <div class="span-20 append-bottom">
99: <!-- <%# form_for :image, #image, :url => image_path, :html => { :multipart => true } do |f| %> -->
100: <%= form_for #image, :url => image_path, :html => { :multipart => true } do |f| %>
101: <%= f.text_field :description %><br />
102: <%= f.file_field :photo %>
103: <%= submit_tag "Upload" %>
What I think the issue is:
When I upload a new image (I'm using Paperclip), it requires the listing_id to create the image record. Since the listing_id isn't passed in with listings/new it can't find the listing_id. How can I pass in the id? Via a redirect? What's the best way to solve this? Thank you.
It seems that the problem is that you are trying to submit to a URL that doesn't exist. If you use a form like this:
<%= form_for #image, :html => { :multipart => true } do |f| %>
Then in your routes.rb file you should have:
resources :images
And you should have an ImagesController with a create action defined. The ImagesController#create action will get called when you submit this form.
The problem is in ur routes.rb file. U have not defined the path, thats why it is giving this error. This might help u
http://guides.rubyonrails.org/v2.3.8/routing.html#restful-routing-the-rails-default
Thank you, your comments have all been helpful.
This is how I wound up solving it:
I added a route for images/new to point to imageController -> Create
<%= form_for #image, :url => "/images/new/#{#listing.id}" , :html => { :multipart => true } do |f| %>
<%= f.text_field :description %><br />
<%= f.file_field :photo %>
<%= submit_tag "Upload" %>
<% end %>

Rails: Form for selecting an existing parent when creating new child records?

I have a has_many and belongs_to association set up between two models: Project and Task.
I'd like to be able to create a form which enables me to create a new Task and assign an existing Project as a parent. For example, this form might have a pulldown for selecting from a list of existing projects.
There are only a finite set of projects available in this application, so I've created Project records via a seeds.rb file. I do not need to make a form for creating new Projects.
I believe I've achieved a solution by using a collection_select form helper tag in the new Task form. I'm pretty happy with how this works now, but just curious if there are other approaches to this problem.
#models/project.rb
class Project < ActiveRecord::Base
has_many :tasks, :dependent => :destroy
end
#models/task.rb
class Task < ActiveRecord::Base
belongs_to :project
end
#controllers/tasks_controller.rb
class TasksController < ApplicationController
def new
#task = Task.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #task }
end
end
def create
#task = Task.new(params[:task])
respond_to do |format|
if #task.save
format.html { redirect_to(#task, :notice => 'Task was successfully created.') }
format.xml { render :xml => #task, :status => :created, :location => #task }
else
format.html { render :action => "new" }
format.xml { render :xml => #task.errors, :status => :unprocessable_entity }
end
end
end
end
#views/new.html.erb
<h1>New task</h1>
<%= form_for(#task) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="select">
<%= collection_select(:task, :project_id, Project.all, :id, :name) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<%= link_to 'Back', tasks_path %>
I just reviewed your code and this looks fantastic to me. One small tweak:
<%= f.collection_select(:project_id, Project.all, :id, :name) %>
This is just slightly cleaner in that you're still using the |f| block variable
Since you mentioned other approaches, I would definitely mention and actually recommend, you use formtastic. The associations are handled automatically and keeps your code clean and also gives you some great customization options.

Resources