Hey all,(im a beginner in rails)
i've created a controller that look like that:
class HomeController < ApplicationController
def homepage
end
def showmsg
#postword = params[:p]
end
end
the showmsg view looks like that:
<%= #postword %>
and my homepage view looks like that:
<%= form_tag( {:controller => 'home', :action => 'showmsg'}, :method => "post") do %>
<%= text_field_tag(:p,#postword) %>
<%= submit_tag("post") %>
<% end %>
now i have a form that i can write something in it and it will show on the showmsg view.
i created a model with the param :posts with a :description "text" field too.
MY QUESTION is how do i implement the model in the code so any thing i write will be in a list with the things i wrote before, because now (obviously) anything if i write something its deleting the one i wrote before.
thank you all!
I would argue that you're approach is not very rail's like... so if you're learning rails... you're learning it wrong.
Make a Model. Call it "Message":
rails generate model Message content:string
remember to migrate (hopefully you have your databases setup properly):
rake db:migrate
Then in your controller, when you post, you can create message like this:
def create #instead of showmsg... 'create' is the standard name for this
Message.create(params[:message])
#messages = Message.all
end
This will create the message in the database, and then it will get all the messages out of the database and put them into #messages.
You need to edit your form so that it uses form_for. You need to pass it #message, which is an instance of Message.new that your first controller action created. You should call this new
In your create.erb.html file, you show all the messages like this:
<ul>
<% #messages.each do |message| %>
<li><%= message.content %></li>
<% end %>
</ul>
I actually wouldn't recommend showing all the messages in the create action - it should really happen in the index action and you should redirect... but we need to keep this simple. Just google this or watch some of Ryan's screencasts and you'll get it.
And you're done. This is the "Rails Way" to do things. It's best to learn it the way they want you to learn it.
I would also commend that you format your code properly by indenting, and start naming your methods to be real english. For example, showmsg is bad and show_message is a lot better.
If all of this is totally confusing, then just create a new project, and then type:
rails generate scaffold message content:string
It will basically build the application you want and a lot more. You can just read the code and see how they did it.
Hope it helps.
Your approach is not really rails like so some tweaks and fixes are needed. Suggestions: check rails approach to REST. The following code will work it is a little more rails like, but still not all the way there.
Generate a model
rails generate model Message postword:string
this will generate the model and create the migration necessary to create the table in the database.
Create the table
rake db:migrate
Define a post action
It will save the postword in the database. In your controller:
def create
#message = Message.create!(params[:message])
if #message.save
redirect_to "/home/showmsg"
else
render :action => "/home/homepage"
end
end
Create and instance of Message to use in your form
def homepage
#message = Message.new
end
Fix your form tag
<%= form_for #message, :url => "/home/create" do |f| %>
<%= f.label :postword %>
<%= f.text_field :postword %>
<%= f.submit "Create" %>
<% end %>
Now let's show the words in the showmsg page
In the controller select the postwords from the database:
def showmsg
#postwords = Message.all
end
Showing them: /showmsg.html.erb
<H1>postwords list</H1>
<ul>
<% #postwords.each do |p| %>
<li><%= p.postword %></li>
<% end %>
</ul>
Your routes.rb file will have this routes:
get "home/homepage"
get "home/showmsg"
post "home/create"
Define an attribute :new_text in a way similar to this:
class TheModel
# Virtual writer - everything assigned to this attribute
# will be added to self.text
#
def new_text=(v)
self.text += v.to_s
end
def new_text
"" # This is write-only attribute
end
end
Now, use the field 'new_text' in your form.
Of course, this is a very simple example. You should decide whether you want to add the content on every call to :new_text=, maybe some validation would help, the read accessor may need some care, and so on.
For some good guides which may help you start, see the site http://guides.rubyonrails.org/
Related
I've been struggling to get this to work following a tutorial. I've got Users that have profiles, and a Client model that, through a 'many to many' join table, establishes the relationships between the user and the clients.
What I'm trying to do is create a list of check boxes generated from the list of clients in the DB that you can tick on or off, and then when you submit it, the user will have the relationship to those clients through the join table.
It's sort of working with static data as you can see below:
/profiles/show.html.erb
<% #clients.all.each do |client| %>
<li>
<%= check_box_tag "user[client_ids][]", client.id %>
<%= client.client_name %>
</li>
<% end %>
<%= link_to 'Add Clients', '../assign_clients/' + #profile.user.id.to_s , class: 'btn btn-default' %>
Routes
get 'assign_clients/:id', to: 'users#assign_clients'
And finally in my users_controller.erb
def assign_clients
#user = User.find(params[:id])
#user.client_ids = [1,2]
redirect_to :back, alert: 'Assigned Users'
end
Obviously it's just using hard coded values of 1 and 2. What I'm not sure how to do is wrap the checkboxes in the correct form tag/simple_form (which I am using), and then with the 'submit' button, have that do the 'assign_clients' action that passes through the values.
Thank you for any help.
What I'm not sure how to do is wrap the checkboxes in the correct form
tag/simple_form (which I am using), and then with the 'submit' button,
have that do the 'assign_clients' action that passes through the
values.
In order to create a form that will trigger the assign_clients method a route needs to be setup in your routes.rb file like the following:
resources :users do
patch 'assign_clients', to: 'users#assign_clients', as: 'assign_clients'
end
This sets up a route for a user that you can use the http patch method with (ie. UPDATE). The plan is to pass the client_ids to the users controller as params from the form. I gave it a path name so that we can reference it in the form as user_assign_clients_path(:user_id)
Now that we have the route set up...using the default rails form tags you can structure the form along the lines of this:
<%= form_for #user, url: user_assign_clients_path(#user) do |f| %>
<% #clients.each do |client| %>
<li>
<%= check_box_tag "user[client_ids][]", client.id, #user.clients.include?(client) %>
<%= client.client_name %>
</li>
<% end %>
<%= f.submit "Add Clients", class: "btn btn-default" %>
<% end %>
This will create a form allowing you to post the selected clients as an array of ids to the assign_clients method.
Finally, the assign_clients method can then retrieve the client_ids from the params hash (via params[:user][:client_ids] most likely) and update the user instance (retrieved using user_id from params hash also). You will probably have to add client_ids: [] to the end of your strong parameters list for user to whitelist it - but this essentially should behave like a typical update method.
def assign_clients
#user = User.find(params[:user_id])
#user.update(user_params)
redirect_to wherever_path
end
def user_params
params.require(:user).permit(
client_ids: []
)
end
You need to understand several basic concepts, let me explain to you:
on: member routing - in order to solve your issue directly, your route should be something like:
resources :users do
post '/assign_clients/:client_id', on: :member
end
so that other than user_id, the :client_id can be also passed in as a parameter. For the details, you can read about rails guides on routing.
For the checkbox way, you need nested_attributes - http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html. So that you can achieve what u need with a simple update call on users.
You can also implement a customised logic, with the client_ids passed in as parameters. In order to learn how forms & parameters work in rails, you can build a form, submit it, and see how it goes in the rails server log.
If anything is unclear, simply comment below & I'll try to update.
I know this is probably a very basic question but I am brand new to Ruby and kinda in a dead end. I have made a simple little site with profiles and profile pages. But on the profile pages I would like to add a new text field like "Bio" for instance where the user types in a bio about himself and it shows. Im just at a blank on how to create a new text field where people can input this stuff. I know this is basic stuff just stuck and looking for some help or guidance to a tutorial or something. Thank you in advance
Here's an example copied from another answer:
<%= form_for(:ad, :url => {:action => 'create'}) do |f| %>
<%= f.text_field(:name) %>
<%= f.text_area(:text, "", :size => "50x10") %>
<%= submit_tag("Submit") %>
<% end %>
This is kind of a complicated question, once you think about it, because there are so many parts.
Ruby on Rails is built on a architecture, called Model View Controller or MVC. The three parts together make the user interface that is presented to the user.
Models are the actual data, like the User objects, in this case. To create the model, type in this command to the console:
rails g model User bio:text name:string
This will make a basic user model, which only contains two columns, a column for the bio, and a column for their name. Note that this is very uncomplicated, and this can be expanded on a lot, but for now it will do.
Or, if you already have a user model, type in this command to the console:
rails g migration add_bio_to_users bio:text
Next are the controllers, controllers are, in a way, what connect the models and the views, so they manage all of the logic in the back end, like creating new users, or adding bios to their profiles.
You can create the user controller like this (if you do not already have one):
rails g controller Users new
And then, you can add this code to the new file generated, to add the functionality of adding bios (and showing them, too) (and updating other columns as well):
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
render #user
else
render #user # Handle error accordingly
end
end
def show
#user = User.find(params[:user])
end
private
def user_params
params.require(:user).permit(:name, :bio)
end
Now, to the final part, which is the view, which is the actual thing that is presented to the user:
<%= form_for(:user, :url => {:action => 'update'}) do |f| %>
<%= f.text_field(:name) %>
<%= f.text_area(:bio, "", :size => "50x50") %>
<%= f.submit yield(:button_text) %>
<% end %>
Note that this is just a simple view that assumes that you also have a column name in your User model, you can change this accordingly.
And, finally, to show the user, add this to the show view:
<%= #user.bio %>
to show the bio in the show view.
Good luck!
I stored all the tablename I've created to Menu table. And every time I add the table in Menu, it will automatically create a link under Menu list
see below.
I want each table in Menu to have a Listing, New, Edit, and Delete.
see below.
I have a controller prj_menus_controller, I will just pass the id of the table from Menu table.
here is the code for index and new in my controller.
Class PrjMenusController < ApplicationController
def index
#prj_menus = Menu.find(params[:id]).tablename.singularize.classify.constantize.all
end
def new
#prj_menu = Menu.find(params[:id]).tablename.singularize.classify.constantize.new
end
def create
#prj_menu = Menu.find(params[:id]).tablename.singularize.classify.constantize.new(prj_menu_params)
if #prj_menu.save
redirect_to :action => 'index'
else
render :new
end
end
private
def prj_menu_params
params.require("HERE IS MY PROBLEM").permit(:name)
end
end
and in my
new.html.erb
<%= simple_form_for (#prj_menu),:url => prj_menus_path, :method => :post do |f| %>
<%= f.input :name %>
<%= f.submit 'Save', class: 'btn btn-primary' %>
<%= link_to "Cancel", :back, {:class=>"btn btn-default"} %>
<% end %>
I can get the list in my index.html.erb, it is working. My problem is that I don't know how to get all params when I click the submit in new.html.erb. I got this hash
{"sample1_table"=>{"name"=>"test 6"}, "commit"=>"Save","controller"=>"prj_menus", "action"=>"create"}
It is correct but I don't know what to put in my controller. I tried this params.require(["#{#prj_menu}"]).permit(:name), it creates new record but params[:name] does not save.
I am still a noob to Ruby On Rails and I don't know what to search for this.
I think you are mostly confused on what parameter whitelisting does and how parameters are passed from the form to the controller.
I does not really matter if the name of the form hash matches the name of the database table. It just does in most cases since that makes the most sense. It's simply representative of the REST interface of your app.
Let's say you have a action which creates Pets:
POST /pets
And in our form we have a bunch of inputs like so:
<input name="pet[name]">
Rails will map create a params[:pet] hash { name: 'Spot' }. But we want to save the pets as an Animal.
class PetsController < ApplicationController
def new
#pet = Animal.new()
end
def create
#pet = Animal.new(pet_params)
if #pet.save
# ...
end
def pet_params
params.require(:pet).permit(:name)
end
end
Animal does not care what the params key is, it just gets a hash. But we also need to tell simple_form what parameter key we want to use since it looks at the model_name attribute.
simple_form_for(#pet, as: :pet)
Gives us pet[name] instead of animal[name].
I don't get why you are so adamant about making things so difficult for yourself though unless you are creating a database administration tool in the vein of PHP_MyAdmin. And even that case you don't even want to be altering the schema of the app database at runtime.
You are going to run into huge problems when it comes to creating effective queries for getting all the menus.
I've just started programming in rails 3 days ago, learned ruby by the same time, and I'm having a hard time since yesterday figuring how to with one form, delete/update some of my instances, I only use one model "Task". Here's the code:
<%= form_for #task do |f| %>
<ul>
<% #tasks.each do |task| %>
<li id="task"><%= f.check_box :done %> <%= f.label :name %> </li>
<% end %>
<button onclick="doUpdate()">Mark Selected as done </button>
<%= button_to "Delete selected", :method => :delete %>
</ul>
<% end %>
Here's the controller:
def delete
#tasks = Task.find(:all, :conditions => ["task.done = ?", true])
#tasks.each do |task|
task.delete
end
#tasks = Task.all
end
My model have only 2 parameters. name:String and done:Boolean, I wan't to delete all the selected checkboxes. But this don't work for me
Thanks in advance.
The problem is, you are doing it wrong(and I'll tell you why). I could paste the code that would make it work but I'd rather explain, as you are probably doing it to learn.
Task.find(:all, :conditions => ["done = ?", true]) will return EVERYTHING in your database where done = true. You will be erasing everything that is marked as done in the DATABASE, not what were marked on the form. Task is your model, you can access the database by using find, where and other methods from activerecord(if activerecord doesn't sound natural to you, activerecord lets you get stuff from the database without the need of writing SQL queries).
What you really need to do in your controller is:
- You have to get what was sent from the form (check the documentation/web resources for the usage of param[] ).
- For every checkbox marked true, you erase a record. (you got the each part right, this is good!)
I don't think your view is right, I advise you to first be sure that the data that you receive is right(the params[]), then proceed to try to erase the record, or do whatever you want to do with it.
To "test" if your variables and code that is inside your controllers and models, use print #variable or something else(check rails docs how to debug).
I advise you use destroy instead of delete as other fellow stackoverflowers have said. Read the docs of destroy and delete.
Keep going :)
On a first glance, try using task.destroy instead of task.delete, and done instead of task.done See delete vs. destroy.
def destroy
#tasks = Task.find(:all, :conditions => ["done = ?", true])
#tasks.each do |task|
task.destroy
end
#tasks = Task.all
end
I have the following model:
class Activity < ActiveRecord::Base
has_many :clientships, :dependent => :destroy, :after_add => :default_client_info
accepts_nested_attributes_for :clientships, :allow_destroy => true
end
In my controller, if I perform the following
def new
#activity = IndividualActivity.new(params[:activity])
#activity.clientships.build(:client => Client.first)
...
end
and then save the form, it creates the relevant params and submits successfully.
However, if I chose to call the following through a remote link
#activity.clientships.build(:client => Client.last)
the view is updated with the new clientship record but when I submit the form, the params[:activity] is not created for the second nested attribute. (Why not!?)
This is the view:
%h1 Create a new Activity
- form_for #activity do |f|
%div
= render "activities/client_selector", :f => f
%div
= f.submit "Save!"
Here is the remote_link's controller action
def add_client
#activity = IndividualActivity.new(session[:individual_activity])
# Refresh client
#activity.clientships.build(:client => Client.find(params[:client_id]))
respond_to do |format|
format.js
end
end
This is the add_client.html.js:
page.replace_html "selected_clients", :partial => 'activities/clients'
This is the activities/clients partial:
- form_for #activity do |f|
- f.fields_for :clientships do |client_f|
%tr
%td= client_f.hidden_field :client_id
%td= client_f.object.client.full_name
Does anyone know how I can troubleshoot this further? I seem to have come to a dead-end with my debugging... One thing to note, there is a double use of the following form_for used in new.html.haml and the activities/clients partial (is this problematic?)
- form_for #activity do |f|
I am on rails v2.3.5
Thanks
You ask about debugging, so the first step may be looking at the server log (log/development.log).
There you should see the "params" hash.
Maybe your params contain "activity"=>{"client_id"=>..} instead of "client_id"=>.. ?
Also look at the generated HTML page - use a Firebug or just use a "view source" method of your browser. Look, especially, for input names.
If everything looks OK, put a few debug calls in your action, and look at the development.log for some database activity - do the SQL queries look like they are doing what you want?
In your question there is no 'save' method. The 'build' method does NOT save the created record. Maybe this is your problem?
def add_client
logger.debug "Creating Activity"
#activity = IndividualActivity.new(session[:individual_activity])
logger.debug "Building clientship"
# Refresh client
#activity.clientships.build(:client => Client.find(params[:client_id]))
logger.debug "#activity = #{#activity.inspect}"
# Maybe you were missing this part of code?
logger.debug "Saving #activity"
#activity.save! # use a ! to easily see any problems with saving.
# Remove in production and add a proper if
logger.debug "Saved. #activity = #{#activity.inspect}"
respond_to do |format|
format.js
end
end
You should create a functional test (in case you haven't already) and ensure that if you send proper parameters, your action works as intended.
The test will narrow your search. If the test fails, you know you have a problem in the action. If the test is OK, you need to ensure the parameters are sent properly, and you probably have the problem in your view.
UPDATE:
You said you have TWO forms on the page. This may be the problem, since only one form may be sent at a time. Otherwise it would need to work in a way which can send two requests in one request.
First thing (useful in all similar problems): validate whether your page has correct HTML structure - for example http://validator.w3.org would be a good start. Try to make the code validate. I know that some people treat a "green" status as a unachievable mastery, but just it's really not so hard. With valid code you may be sure that the browser really understands what you mean.
Second: Place all your inputs in a single form. You have problems with nested attributes. For start, try to manually insert inputs with name like <input name="activity[clientship_attributes][0][name]" value="John"/>, and for existing clientships ensure that there is an input with name = activity[clientship_attributes][0][id].
This is the way nested attributes are handled.
Your view may create such fields automagically. This construction should be what you need: (it worked in one of my old project in rails 2.x, I have just replaced the names with ones you use)
<% form_for(#activity) do |f| %>
<p><%= f.text_field :activity_something %></p>
<% #activity.clientships.each do |clientship| %>
<% f.fields_for :clientships, clientship do |cform| %>
<p><%= cform.text_field :name %></p>
<p><%= cform.text_fiels :something %></p>
<% end %>
<% end %>
<% end %>
If you really want to use a partial there, don't create a new form in the partial. Use only the parts of above code.
To pass a variable to the partial, use :locals attribute in the place where you call render :partial:
<%= render :partial => 'clientship', :locals => {:form => f} %>
Then, in your partial, you may use a local variable form where you would use f outside of the partial. You may, of course, map the variables to the same name: :locals => {:f => f}