I am really really stuck and annoyed with this right now.
I am running Rails 2.3.5
My View/pages/customers.html.erb simply has:
<% form_tag do %>
First Name
<%= text_field_tag :firstName, params[:firstName] %>
Last Name
<%= text_field_tag :lastName, params[:lastName] %>
<%= submit_tag "Enter" %>
<%end%>
My Models/customer.rb simply has:
class Customer < ActiveRecord::Base
attr_accessible :firstName, :lastName
end
My Controller/pages_controller has
class PagesController < ApplicationController
def custs
#cust = Customer.new(params[:firstName], params[:lastName])
#cust.save
end
end
so as you see I am just trying to enter two fields from front end and then save them to the DB. However, whenever i load my page it give me error:
wrong number of arguments (2 for 1)
pages_controller.rb:3:in new'
pages_controller.rb:3:incusts'
weird thing is that when I use the sandbox script/console I am able to insert data fine.
What is going on here? please someone explain!
http://apidock.com/rails/ActiveRecord/Base/new/class here is a little explanation of the new function. The crucial part - "pass a hash with key names matching the associated table column name". Instead of #cust = Customer.new(params[:firstName], params[:lastName]) you should have #cust = Customer.new(:firstName => params[:firstName], :lastName => params[:lastName]). This should do the trick.
The quick fix is to change line 3 of pages_controller to this:
#cust = Customer.new({:firstName => params[:firstName], :lastName => params[:lastName]})
Without proper keys Rails has no idea what values you are passing and in what order.
The bigger problem seems to be that your form is not setup properly. You might have a great reason for it, but if not, I would recommend creating a blank Rails project, and using generate scaffold to see how a normal Rails form/controller is setup.
Since new takes a hash, from which attributes will be set where the hash has the corresponding keys, Customer.new(params) should be sufficient, shouldn't it? Unless params also has keys for attributes that you don't want to be set in this case, I suppose.
Obviously your sample code may have been edited-down to better present the problem, but as shown, the #new/#save pair can usually be condensed down to Customer#create(params)
Related
I am relatively new to rails but having a real problem with something that I know should be really simple. I have a model called channel, in it I have a simple new method, in the view I have form but every time I try and load it, I get an error to say:
undefined method `channels_path'
My view (new.html.erb) is really simple, for the minute it just has a button in it with a name and a value, it just looks like this:
<%= simple_form_for #channel do |f| %>
<%= f.error_notification %>
<%= f.button :submit, 'Free Plan', name: 'plan', value: 'free' %>
<% end %>
My Controller has:
def new
#channel = Channel.new
end
And in my routes I have:
resources :channel
Output form a rake routes is:
channel_index GET /channel(.:format) channel#index
POST /channel(.:format) channel#create
new_channel GET /channel/new(.:format) channel#new
edit_channel GET /channel/:id/edit(.:format) channel#edit
channel GET /channel/:id(.:format) channel#show
PATCH /channel/:id(.:format) channel#update
PUT /channel/:id(.:format) channel#update
DELETE /channel/:id(.:format) channel#destroy
Which all looks how I expect. But as the error says there is no channels_path, but as far as I am aware, there shouldn't be.
I am sure this is supposed to be really simple but I just cannot see what I am doing wrong. Can anybody help?
Many thanks
David
EDIT
I have updated the route to be:
resources :channels
I can now load the form, however I now get the error when trying to submit it:
param is missing or the value is empty: channel
Being caused by:
# only allow specific params
def channel_params
params.require(:channel).permit(:name,
:slug,
:description,
:plan,
:subscription_ends
)
end
I am assuming singular is correct here based on the model, but have tried plural too with no luck. Any more thoughts?
Many thanks
Edit
Got it working in the end, it appears you have to have at least one input in your form. I added an input for the name field and it started working.
Many thanks to everyone that commented
According to your rake task, the path should be
channel_path
If it's not working with the simple_form_for helper, it's probably because you should have set up your routes as resources: channels
UPDATE
The new bug is coming from nothing being received by the controller for :channel
Try adding a field like so
f.hidden_field :plan, :value => "free"
I'm trying to read parameters from html form and update some fields in the database...
Html is showing data from multiple "stories" and I want to be able to change Story.estimate field...
The html has text input fields for every story showing like so:
<%= text_field_tag story.id, story.estimate, :class => "input-small" %>
My idea was to name these input fields by the ID of their story and then read and update them in the controller like so:
#story.update_attribute("estimate",params[#story.id])
But this of course does not work... I need some help... There has to be a better, simpler way of doing this...
You should try
<%= text_field_tag "story[#{story.id}]", story.estimate, :class => "input-small" %>
and in your controller
you will get the params like this
if params[:story].present?
id = params[:story].keys.to_i
value = params[:story].values.first
#story = Story.where(id: id).first
#and then finally update the story
#story.update_attribute("estimate",value)
OR
#this will also update your story for the corresponding story id
Story.where(id: id).update_all(estimate: value)
end
Also, I believe update_attribute may have been removed in rails 4 in favor of update_column. So if you are running rails 4 that may be an issue. (https://github.com/rails/rails/commit/a7f4b0a1231bf3c65db2ad4066da78c3da5ffb01)
I have a user view and a rental view.
In my rental view im trying to show the current users name. I think I am pretty close but I can't work out this last bit.
This returns all of my users in a select list
<%= f.select :user_id, User.find(:all).collect {|t|
[t.user_name, t.id]} %>
This returns my current users ID
<%= f.number_field :user_id %>
So I thought I could do something like
<%= f.select :user_id, User.find(:user_id).collect {|t|
[t.user_name, t.id]} %>
Which I would want to only return the current user in a select list with their id as the value and their name in the list. If I do the above it tells me
Couldn't find User with id=user_id
So user_id is being passed as a literal string but I want to pass the user_id variable which should be somthing like 10. I don't know how to pass the user_id as a variable.
I'm fairly new to ROR, I might be going about this the completely wrong way. Any help is much appreciated.
I am assuming you have a rental object, for which you show the form, I assume it is an instance variable #rental, furthermore I assume that inside your Rental class there is the following relation
class Rental
belongs_to :user
end
Then you could just write the following:
f.select :user_id, [[#rental.user.user_name, #rental.user.id]]
Hope this helps.
On a related but less important note: it is really weird to have a column called user_name for a user: I would call that column just name, since it is part of a user anyway.
find() wants a variable, not a symbol. And :all probably isn't what you want. You should write a method in your controller like:
def user(u)
#user = User.find(u)
end
Then call the method in the view or whatever like (I don't know exactly what you're trying to do here):
<% user(current_user.id) %>
Then you'll have a #user object with which you may play, i.e.:
<%= f.select :user_id, [[#user.name, #user.id]] %>
I think you should be able to do:
<%= f.select :user_id, User.find(f.object.user_id).collect {|t| [t.user_name, t.id]} %>
This does seem a little odd to me though. I'd have thought either:
Your object has a proper association to the relevant user, in which case you should be able to do f.object.user.user_name and f.object.user.id.
If you genuinely want the currently logged in user, you should probably be asking your authentication framework/code for the reference. E.g. if you were using Devise, it would be current_user.
As an aside, I don't really understand why you want a select list just containing the current user - is that definitely what you're trying to achieve, or have I misunderstood?
This is probably a very simple fix but I've been unable to find an answer just yet.
My application has orders and tasks. Orders have many tasks. When a user clicks new task in the show order view, it passes the order.id:
<%= link_to "New Task", new_task_path(:order_id=> #order.id) %>
The url shows:
/tasks/new?order_id=1
I just don't know how to extract this and use it in my form? I have tried:
<%= f.text_field :order_id, :value => #order_id %>
But it's not working.
You can do:
<%= f.text_field :order_id, :value => params[:order_id] %>
Alternately, capture the value (with params) in the controller and assign it to #order_id there.
You are doing this wrong, which is a big deal in Rails where convention-over-configuration is such an important ideal.
If an order has many tasks, your route should look like this:
/orders/:order_id/tasks/new
And your routes should be configured thusly:
resources :orders do
resources :tasks
end
You should [almost] never find yourself passing around record ids in the query string. In fact, you should almost never find yourself using query strings at all in Rails.
On a Content model have an attribute named slug. When creating a new record, I want to use a helper to populate this field, but on an existing record I want to use the value from the database.
Currently I have:
<% if #content.new_record? %>
<%= f.text_field :slug, :value => "#{generate_slug(6)}" %>
<% else %>
<%= f.text_field :slug %>
<% end %>
But that seems a bit verbose. Is this the best way, or is there no other way? (Rails newb just trying to find the "Rails way" on issues I'm unsure of)
Edit
I should note that the helper is currently in /app/helpers/application_helper.rb Moved to be a private action in the Contents controller. David's answer worked great.
In your controller
#content.slug ||= generate_slug(6)
This will assign a value to the slug attribute if none is present
Then, in your view you can simply use
<%= f.text_field :slug %>
Options
Try after_initialize callback in your model.
Try creating a method in your model where you set defaults and call it in your new action in the controller. Also call this method if your create fails and you render new. Remember to set default only when no value exists by using the ||= operator.
Example to follow. I'm typing on phone!
I happen to use jQuery in my projects, so when I want some functionality like this, I usually use something like labelify. Then, I'd use something like <%= f.text_field :slug, :title => generate_slug(6) %>. (Hot tip, you don't need to put the #generate_slug call inside of a string if it returns something that will resolve to a string by itself, in fact it's more performant if you don't.)
If you don't want to go with jQuery approach, you might want to wrap this piece of logic in your model.
def Content < ActiveRecord::Base
def slug
self.new_record? ? self.slug_for_new_record : attributes[:slug]
end
private
def slug_for_new_record
# I don't know what you're doing in generate_slug, but it sounds model-
# related, so if so, put it here and not in a helper
end
end
If it really belongs in the view, still another option is to just make your Ruby a little bit more concise (you'll have to judge if this is more readable):
<%= f.text_field :slug, :value => (generate_slug(6) if #content.new_record?) %>
Don't forget the parens surrounding (generate_slug(6) if #content.new_record?). If you do, the if will be applied to the text_field, which is not what you want.
But there are still more ways to do it. The above line of code isn't great if your logic might change and you're pasting this code all over your rails project. When I wanted to add a 'required' class to my text fields but only if they were a new record (we had some legacy data that we didn't want to make people clean up), I created my own form builder with a required_field method that just called text_field and added a 'required' class if the item was a new record. This might seem like a work, but we have around 20 different forms, each with potentially multiple required fields, and it's a lot easier to change the business logic in one place. So if you really think this logic belongs in the view but you've got a ton of these lines of code and you don't want to have to change it in a million places, then FormBuilder is the way to go. I think this is in most cases prettier and more appropriate than a helper, but again, beauty is in the eye of the beholder. Here's my code somewhat adapted for your case:
# config/environment.rb
ActionView::Base.default_form_builder = NamespacesAreFun::FormBuilder
# lib/namespaces_are_fun/form_builder.rb
module NamespacesAreFun
class FormBuilder < ActionView::Helpers::FormBuilder
def slug_field(method, options = {})
opts = options.to_options
opts.merge!(:value => generate_slug) if self.object.new_record?
text_field(method, opts)
end
end
end
# views/.../your_view.html.erb
<%= f.slug_field :slug %>
Hopefully in all of these different approaches is one that fits your project.