I have a model that uses the same form for both create and update controller actions.
Nothing special there. I have the submit button changing its text based on which action using en.yml
en:
helpers:
submit:
location:
create: "Add to map"
update: "Save changes"
How would I go about changing a body of text on this form, according to the appropriate action?
Eg, if it was create,
<h1>Create new location</h1>
and if update
<h1>Update location</h1>
You could simply add the text to your en.yml file:
en:
create_new_location: 'Create new location'
update_location: 'Update location'
And then use the following in your view (create/update)
<h1><%= I18n.t(params[:action] == 'create' ? 'create_new_location' : 'update_location') %></h1>
Or, if you were using new/edit:
<h1><%= I18n.t(params[:action] == 'new' ? 'create_new_location' : 'update_location') %></h1>
You could also make your translation based on the action and embed that in the translation text, by doing something like this:
I18n.t "location.action.#{params[:action]}"
I would recommend against this though, because it's harder to tell what text you are actually translating.
Related
I'm rendering a form on a few different pages, such as: edit, new, show. Now on the submit button it says: "update post" and "create post". I know that there is a way to add custom text to the buttons <%= f.submit "Text" %>. But because i'm rendering the form it shows that value on each of the pages. So i'm wondering if there is a way where i can add the custom text value per page, without having to copy the whole form itself.
You can use the Rails built-i I18n (internationalization) module:
# config/locales/en.yml
en:
helpers:
submit:
post:
create: "Toss me bottle to the sea!"
update: "Arg! Now she be a spellin' straight."
You need to remove the text from submit button in order for it to be translated:
<%= f.submit %>
I am rendering a form using form_for with an existing model. I would like to submit that model and get the next action to be performed to be the 'create' action. The docs have this example:
<%= form_for #post do |f| %>
<%= f.submit %>
<% end %>
And say "In the example above, if #post is a new record, it will use “Create Post” as submit button label, otherwise, it uses “Update Post”."
I am relatively new to rails and am not sure what to make of the following stuff in the docs about customizing using I18n. How can I get the submit button to use "Create" when there's an existing record?
Clarification. . .
I the form_for is being rendered out of the new action, but I am passing it an existing object, so that fields can be prepolulated. I want it to then go to the create action, but it is going to the update instead.
Update. . .
I realize now that the issue is with the form_for and not the submit, but haven't yet figured out how to modify the form_for so that it sends to the create action.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-submit
There are three options, you can either override it in the translations file (config/locales/en.yml).
en:
helpers:
submit:
create: "Create %{model}"
update: "Create %{model}"
Or you can specify a value on the submit method.
f.submit("Create Post")
Or, you can keep the translations file as it is by default and do:
f.submit(t('helpers.submit.create'))
form_for will update a existing record instead of create, so basically you have to feed it a new record. The best way to do this is in the controller with record.dup. Something like
#post = #existing_post.dup
dup will create a shallow copy, allowing you to save it as a new record.
I am starting with Cucumber and I am running this simple scenario:
Scenario: Creating a project
Given I go to the new project page
And I fill in "Name" with "xxx"
...
The new project form is already in place and looks like this:
<% form_for (#project) do |f| %>
<%= f.text_field :name %>
...
<% end %>
As you can see I haven't defined a label (don't need one). The problem is that cucumber doesn't find the field:
Given I go to the new project page
And I fill in "Name" with "I need something" #
features/step_definitions/web_steps.rb:68
cannot fill in, no text field, text area or password field with id,
name, or label 'Name' found
(Capybara::ElementNotFound)
However it finds it if I add the label. I find it a little bit suspicious that it can't match the name I gave with the appropriate text field.
What is wrong?
Thank you
Try changing your cucumber feature to read:
Scenario: Creating a project
Given I go to the new project page
And I fill in "project_name" with "xxx"
Or...
Scenario: Creating a project
Given I go to the new project page
And I fill in "project[name]" with "xxx"
The reason this is failing is because if you have no label, capybara (which cucumber uses) looks for the ID or name attribute of the field. As apneadiving mentions, you can check these values by looking at the source of the generated file. You'll see something like:
<input id="project_name" name="project[name]" type="text">
The name of your textfield is by default:
project[name]
Actually it follows the rule:
object[field]
You should look at your dom and check it.
Edit:
Jus FYI, It's weird to see:
<% form_for (#project) do |f| %>
instead of:
<%= form_for (#project) do |f| %>
I had the same problem and I fixed it by simply changing
<% form_for ... %>
to
<%= for_for ... %>
The addition of the '=' enables the display of the form fields, which allows Capybara to correctly identify it.
Say I have an Article model, and in the article 'new' view I have two buttons, "Publish" and "Save Draft".
My question is how can I know which button is clicked in the controller.
I already have a solution but I think there must be a better way.
What I currently used in the view is:
<div class="actions">
<%= f.submit "Publish" %>
<%= f.submit "Save Draft", :name => "commit" %>
</div>
So in the controller, I can use the params[:commit] string to handle that action.
def create
#article = Article.new(params[:article])
if params[:commit] == "Publish"
#article.status = 'publish'
// detail omitted
end
#article.save
end
But I think using the view related string is not good. Could you tell me another way to accomplish this?
UPDATE: Since these buttons are in the same form, they're all going to the 'create' action, and that's OK for me. What I want is to handle that within the create action, such as give the Article model a 'status' column and holds 'public' or 'draft'.
This was covered in Railscast episode 38. Using the params hash to detect which button was clicked is the correct approach:
View:
<%= submit_tag 'Create' %>
<%= submit_tag 'Create and Add Another', name: 'create_and_add' %>
Controller:
if params[:create_and_add]
# Redirect to new form, for example.
else
# Redirect to show the newly created record, for example.
end
it can also be done on the form_for helper like this
<%= f.submit "Publish",name: "publish", class: "tiny button radius success" %>
<%= f.submit 'Mark as Draft', name: "draft", class: "tiny button radius " %>
and the logic is the same on the controller
if params[:publish]
// your code
elsif params[:draft]
// your code
end
We solved using advanced constraints in rails.
The idea is to have the same path (and hence the same named route & action) but with constraints routing to different actions.
resources :plan do
post :save, constraints: CommitParamRouting.new("Propose"), action: :propose
post :save, constraints: CommitParamRouting.new("Finalize"), action: :finalize
end
CommitParamRouting is a simple class that has a method matches? which returns true if the commit param matches the given instance attr. value.
This available as a gem commit_param_matching.
I remember coming across this problem once. You cannot keep two buttons and then call some action based on the params[:commit]. the submit button onclick is going to call the url the form refers to. There are certain bad ways to get the desired behavior. Keep a button to call the action the form refers to and to get another button to call a action, I used a link_to and then changed the styles to match a button. Also, alternatively you can use jQuery to change the url the form would call, hence deciding what action is invoked at run-time. Hope this helps.
You could also set some data attributes on the submit buttons and use JavaScript to change out the form action on click of one of the buttons
usually i using the suggestion given by John Topley (see answer above).
another way is using JQuery /JS changing the form action attribute- upon clicking the submit button
example:
form_tag({} ,:method => 'post', :id => 'reports_action') do
.......
.......
submit_tag 'submit', :onclick => "return changeAction();"
end
and then .....
function changeAction(){
$('#reports_action').attr('action','my_new_action');
}
I've created simple rails page using 'ruby script/generate scaffold subject name:string desc:string' command.
Now, I can add, edit and delete subject in RESTful way.
What I' like to do is changing above behavior as Ajax way.
Everything can be done in index page. For example...this is the page throw the browser~
screen 1
Listing subjects
name desc
test1 test1 show edit destroy
test2 test2 show edit destroy
[___] [___] create
If you click edit link, the page will transform like bellow
screen 2
Listing subjects
name desc
[test1] [test1] update <-------- this !!! text_field !
test2 test2 show edit destroy
And you can change name and desc. After change the values, clicking update link will update it and browser will display similar page with screen 1
Also, you can add new subject with just filling empty text field bottom of the list and clicking create link. It will be applied immediately.
I tried to find this out but railscasts and even some other webpage did not help. :(
Do anybody know where the sample code for this is or please write simple one !!!
I really appreciate it if you do so...........
wrap each row that you want to dynamically update in a form_remote_tag. When the update button is clicked, the form fields are sent via ajax to the server.
<% form_remote_tag :action => :update do %>
<%= text_field_tag :name, #name %>
<%= text_field_tag :desc, #desc %>
<%= submit_tag "Update" %>
<% end %>
Then on the server side do something like this:
def update
#do normal update stuff
#send RJS back to the user that we did something.
render :update do |page|
page.alert "item updated!"
end
end