I've been struggling for a while on this (been reading a lot of the ruby on rail guides to try and understand this), but I'm not sure how user inputs work.
I am trying to search for a restaurant in my database with a list of fields the user specifies (cuisine, zipcode, review score). I have created a html.erb page that has the options for all of these.
Here is my controller.
class WelcomeController < ApplicationController
def home
#my_search = Restaurant.joins(:inspection).where(cuisine: c, zipcode: z, totalscore: 1..h)
end
My models for restaurant and inspection also have relations between them (the foreign keys).
How would you go about letting the user give inputs for c (cuisine), z (zipcode) and 1..h (score range)?
I know that people have answered this question in the past, but I think I need a concrete example to actually understand how to do this. As in, what would you put in the html.erb code so that when an option is selected, that value is passed to the method?
Thank you
First you need to create a form in the view. The simplest way to do this is with form_tag:
<%= form_tag(home_path) do %>
<%= text_field_tag 'cuisine' %>
...other inputs
<% end %>
Next, make sure you have a route defined for your controller action in config/routes.rb
post 'home' => 'welcome#home'
Most likely your routes will look different but this is the bare minimum you need.
And in your controller you can access the submitted data using the params object
class WelcomeController < ApplicationController
def home
#restaurants = Restaurant.joins(:inspection).where(
cuisine: params[:cuisine],
# ...other params
)
end
end
Related
I want to add a column in a mysql table from a controller. The user completes a form, and when he sends it, it creates a new column (not row) with the information in the form. How can I do this?
it create new column
Don't.
Your database is sacrosanct, dynamically altering it is like dynamically changing a car based on some user's request. A car has four wheels, engine and seats. You can change the colour, tyres, etc... but not the fundamentals.
It's the same with web apps - you should not be changing the fundamental structure of your system. Sure, you'll be able to change various aspects of it (User Avatar etc), but the underlying basis of the system (the db schema) should be kept above any changes.
What you should be doing is maintaining your database fidelity through a tight set of Models, allowing you to create a dynamic experience around the data you've been provided.
For example...
The user complete a form and when he send it, it create new column
A better way to explain this will be to use a user story.
I'll surmise the following in your case:
A user wants to add a new project to his portfolio. He fills out the form to explain what the project will be and adds a number of extra fields specific for that project.
I think you're asking about the "extra fields" part...
You have to remember Rails is built on top of a relational database:
This means that you have the flexibility provided by your models to grant your users the capacity to add and manipulate as many pieces of associated data as they need.
The data they add to the system can have any name & any structure, so long as you provide that functionality within the system itself...
#app/models/user.rb
class User < ActiveRecord::Base
has_many :projects
has_many :specialized_fields, through: :projects
end
#app/models/project.rb
class Project < ActiveRecord::Base
belongs_to :user
belongs_to :specialized_field
accepts_nested_attributes_for :specialized_field
end
#app/models/specialized_field.rb
class SpecializedField < ActiveRecord::Base
has_many :projects
has_many :users, through: :projects
end
According to my example above,
User can make a Project
Project can have specialized fields (above the standard fields)
User can add specialized fields to the model
Thus you can do the following:
#app/controllers/projects_controller.rb
class ProjectsController < ApplicationController
def new
#project = current_user.projects.new #-> assuming you're using Devise
#specialized_field = #project.build_specialized_field
end
def create
#project = Project.save project_params
#project.save
end
private
def project_params
params.require(:project).permit(:name, :start_time, :end_time, specialized_field_attributes: [:name, :value])
end
end
The form could be as follows:
#app/views/projects/new.html.erb
<%= form_for #project do |f| %>
<%= f.text_field :name %>
<%= f.fields_for :specialized_field do |s| %>
<%= s.text_field :name %>
<%= s.text_field :value %>
<% end %>
<%= f.submit %>
<% end %>
Why would you like to add new columns to the database via the controller? This shouldn't be the case - and in general I couldnt' think of a single reason why this should ever be required. It sounds unconventional and against design principles.
If you add more information of what is required and what you are tyring to do I am pretty sure we can work out an alternative solution. (I bet what you are trying to do can be achieved with a many-to-many relationship, or similar, somehow). Post more information and see what we can do.
But as answer and solution I'd say it shouldn't be required.
Why do you want to do this? Database design is part of the application development, so you are the one deciding the rows. When the user inputs data, there are a gazillion things that can go wrong (hacks, invalid values...), which can affect your entire database. It's not worth risking that.
If you want a flexible schema, you can store hashes in a specific field.
For example you have a extra_data field which is a hash. Then in your form you can have to inputs, input_name and input_value which will go to the hash. This way you will have more flexible values for the same column and you don't need to change your database schema.
I have a database with users, vendors, and accounts.
user has an account, account has an integer value credits
vendor has an integer value, product count
I want to be able to have a button on my app that when a button is clicked it will update these two items in the database:
current_user.account.credits
vendor.product_count
I am still vert new to rails and don't really know how it all works yet, so would love some help :D
My git repo on bit bucket so you can examine the code:
https://umlungu#bitbucket.org/umlungu/mybeans.git
On the button_to, you supply parameters that get passed into the controller, and the controller operates based on the received parameters. So far you've not given any information about what controller, what view, or whatever, so the answer is likewise general in nature.
In the view:
<%= button_to 'Something', {controller: "some_controller", action: "some_action", credits: credits, vendor_id: vendor.id} %>
In the controller "some_controller"
def some_action
credits = params[:credits]
credits ||= 0
vendor_id = params[:vendor_id]
# find the current user, and update its credits
# find the vendor and update the product count?
# send your user somewhere
end
end
I have a checkout button on my product page show view which accepts the offer. Each offer belongs_to a user. I don't want the user who created the offer to be able to accept it themselves so if it is the current user on the page I want to hide the button. I can't figure out why this code doesn't work:
<% unless current_user.id == #offer.sender_id %> #sender_id is a foreign key in the offer model that makes each offer belong_to a user.
<div id="accept_offer">
<%= button_to 'Accept Offer', etc %>
</div>
<% end %>
current_user is a devise gem method I believe.
Any help appreciated.
your code seems correct, you maybe need to look into your Offer.sender_id attribute in the model to see if it contains the right user id (of the creator of the offer). You could check that by creating a new offer throught your application (in the browser) then, in the console you type:
Offer.last.sender_id
And check if it corresponds to your current_user id
Just saw the error and got the reason.
You tried the page without sign in so unless current_user works, this means you have not signed in. Your original code doesn't considered this case.
Generally you should see an error as current_user is not defined but you may have disabled that.
Two ways to fix:
Change current_user, assign an object in any case
class ApplicationController
def current_user
super || User.new
end
end
Change the logic
<% if current_user && current_user != #obj.sender %>
# Button code
# Only signed in user with different id can see it
I need some advice. I'm making an app that is a little complicated to learn. It has a user model. Once a user signs up, I'd like a modal dialog to appear the first time (and only the first time) he/she access certain pages. For example, there's a "vote" page and a "create a poll" page, etc.
What's the best way to implement this type of help system? I thought of adding a column to my user model that can contains a default list of values like "vote,create,share." When the user accesses the page that corresponds to one of those actions, if the name of the action is still in the list, the modal appears and the name of the action is removed from the list.
Does this sound reasonable? I know that in a normalized database, you shouldn't store multiple values in a single field. But it seems crazy to create a table called "actions" and another joining table to relate users to actions. There are only 4 or 5 things the user can do on the site.
Or is there some other way to do this that I'm missing? Thanks in advance for your advice.
You should probably make a UserTrigger model that can be used to "trigger" certain actions like this. It would look something like this in practice:
<% for_trigger(#user, :first_time_help) do %>
...help content...
<% end %>
This method would have a definition approximately like:
def for_trigger(model, name)
if (model.triggers.where(:name => name.to_s).delete_all > 0)
yield
end
end
A softer version would have a should_trigger? and did_trigger! method pair, where one would test and the other would actually remove the trigger record. This single-shot one should be good enough for most cases.
You would have a definition in your User model roughly like:
class User < ActiveRecord::Base
has_many :triggers,
:class_name => 'UserTrigger'
end
class UserTrigger < ActiveRecord::Base
belongs_to :user
end
You will have to pre-populate these trigger records after_create on your User model, or any other models that require it. To re-set the trigger, just re-add the record.
I have a Rfq contoller i am creating new or updating existing Rfqs, when i create or update the object is saved, what i want is as i have number of quotes params i want to update the line_items table with the quotes in params[:quotes] in quote_price column after saving the Rfqs
i know its confusing, but who are ror-ish should have got some hint wat i want to ask.
If you're trying to use the params hash in your model, you are violating principles of MVC. The model should stand alone with arguments. If you are trying to do the following:
# controller
Model.foo
# model
def foo
params[:bar].reverse!
end
You should do the following instead:
# controller
Model.foo(params[:bar])
# model
def foo(foobar)
foobar.reverse!
end
Honestly if it deals with params, it's probably a good idea to put that type of logic in the controller, lest you muddle the responsibilities of the model and controller.
That is, in the controller:
if #foo.save
# Update line_items using params[:quotes]
end
I think you want to be able to have 1 form that saves both the main object and all of the child objects. If not, disregard.
In rails, this is named "nested_attributes"
you'll add this to your model:
accepts_nested_attributes_for :quotes
# assuming you have
has_many :quotes
and then in your form view:
<% form.fields_for :quotes do |child_form| %>
<%= child_form.text_field :name %>
<% end %>
Check this out at Ryan's Blog: Nested Attributes