I just started trying to get acquainted with Rails, and I don't really know much Ruby. Currently I'm doing a beginners project to get acquainted with the framework which involves a simple form which takes a name, email, and phone number, and when you hit a submit button the page should refresh and present the information you submitted (so there is no database interaction and the model is supposed to do very little). It's very simple, but as my current knowledge of Ruby is pretty minimal, I'm getting somewhat confused. I've written the views for the most part but I'm still confused on what to put in the controller and the model. If anyone could provide any hints that would be great!
You need tableless model. Please refer excellent webcast from Ryan on this topic.
http://railscasts.com/episodes/193-tableless-model
Models (at least those descending from ActiveRecord::Base) require a database, so if you are using a model you are using a database, even if its a simple one like SQLite.
If you don't want to descend into models and generating a migration to create the tables for your models, then you are probably just going to store the form values into instance variables and reference those in your view. Below is a quick example how to do that.
If you have a form that sends data (ex: name and email) to a create action, the create action would look sort of like this:
def create
#name = params[:name]
#email = params[:email]
render :my_template
end
The create action above is assigning the params sent to it to instance variables, which you can then reference in your view. In the above example the create action is going to try and render a view called my_template which would probably be named my_template.html.erb and might look something like this:
<p>Your name is <%= #name => and your email is <%= #email =>.</p>
This is an extremely small and contrived example, but hopefully this helps.
When you move on to working with models your create action might instead create a new instance of a model, pass that model the params sent by the user, save the model, and then redirect them to a page that shows the data.
It is much easier with a database.
rails new stack
cd stack
rm public/index.html
rails generate scaffold Member name:string email:string phone:string
rake db:migrate
rails server
Then browse to localhost:3000/members
(Assuming you are using rails 3)
Related
I've a user profile (with name, logo, about_me) which is created after user creation(using Devise). Profile table uses user_id as Primary key.
Now I want that whenever the user creates/updates a post, while filling in form some details are taken from profile, so profile data or #profile be available in post form as I cannot expose my model in form.
To set post.myname attribute in create and #update I'm doing this:
#myprofile = Profile.find_by_user_id(current_user)
write_attribute(:myname, #myprofile.name)
I read from various sources but what's the best solution of the 4 given and if anyone can back with easy code as I do not want to do something extensive? Thanks in advance.
1)Form Hidden fields - Like get the profile data as above in hash in #edit and then pass through form and access fields in #update but that way we will pass each field separately. Can one #myprofile be passed?
2)Session - I feel if profile data is stored in a session and someone updates profile then updated data won't be available in that session.So not sure if it is plausible.
3)Caching - easy way to do that?
4)polymorphic profile---tried it but I didnot get relevant example. I was stuck with what to put as profileable id and type and how to use them in the code.
If your Profile and User models have a one-to-one relationship with each other, the simplest solution is to remove the Profile model altogether and move its fields into the User model.
Devise already queries the database to obtain the current_user object. So, your example would like this:
write_attribute(:myname, current_user.name)
Which wouldn't hit the database (after Devise has retrieved the current_user object).
If you're forced to keep the Profile model, in looking at your four scenarios ...
You could use a session variable. Something like:
session[:profile_name] ||= #myprofile.name
This would go in a controller action.
The trick here is that you will want to redefine the each relevant session variable if the profile gets updated. And because you don't have access to the session in the model, you'd be best to perform that action in the controller. So, not pretty, but it could work.
You could also use low-level caching, and save the profile relationship on the user. In general, you could have a method like this in your user model:
def profile_cached
Rails.cache.fetch(['Profile', profile.id]) do
profile
end
end
Here, too, you will have to know when to expire the cache. The benefit of this approach is that you can put this code in the model, which means you can hook its expiration in a callback.
Read more about this in Caching with Rails.
I would avoid hidden fields and I'm not sure how a polymorphic relationship would solve you not hitting the database. So, #2 and #3 are options, but if you can combine the two models into one, that should simplify it.
I'm making a versioned JSON API in rails, where the controllers also respond to HTML, meaning it can be accessed as a browser or through an app I'm developing. The controllers have the form Model::V1::UsersController (Model instead of API since they don't just respond to JSON), and I currently have the following in my routes.rb:
namespace :model, path: 'm', as: '' do
# For objects in the model, accessible by JSON (through the app) or HTML (through the browser, using forms to send data to the server).
scope module: 'v1', constraints: OrConstraint.new([APIConstraint.new(1), APIConstraint.new(:default)]) do
resources :users do
collection do
post :sign_in
end
end
end
end
I plan to add more models to my API, but how can I use scaffolding to do this? For example, to create a controller Model::V1::CommentsController, but using the Comment model, instead of Model::V1::Comments.
I've been trying to figure this out for hours, and googling for people with similar problems shows that a few people say not to use scaffolding at all in this case: I don't want to do this, as it would mean writing all the views myself, which would be very time-consuming. Apart from that, I can't find much. nifty-generators was suggested somewhere, but it doesn't seem to be maintained anymore: no activity since 2012. I'm new to rails, and it might be that I've missed something quite obvious, but I find it surprising that not many others have had the same issue.
I've considered making my own generator, but looking at the source of https://github.com/rails/rails/blob/master/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb, it seems very complicated.
EDIT: I've just discovered that I can pass the --model-name parameter to the rails scaffold generator to achieve what I want, but for some reason it still tries to create a model with the same name as the controller. How can I change this?
I've settled with this solution, by not generating a model at all using the scaffold generator:
To create Model::V1::CommentsController as the controller and Comments as the model:
rails g model comment
rails g scaffold model/v1/comments --model-name=comment --no-orm
I created an object named settings. So i also provided its route in the routes.rb file i wrote "map.resources :settings". Now as i'm trying to save to the database with that object, it keeps on getting to the localhost:3000/settings url, which i don't have. i', also having this error
NameError in SettingsController#create
uninitialized constant SettingsController
PLEASE HELP! THANKS!
I am not 100% sure, but I believe you need to have a controller to add a route. Check out this diagram: http://ruby.railstutorial.org/ruby-on-rails-tutorial-book#sec:mvc
If you use Rails, you have to stick to its rules. Rails implements the MVC pattern, where the controller has the role to provide the linking between a request started in the client web page (view) to creating, reading, updating and deleting (CRUD) objects (== models). The routes.rb define here the mapping from the URL to controller actions, not directly to the resources. See the "Rails Guides for Routing" for more information.
If you want to use your model objects, Rails provides an easy way to start that: scaffolding. By using rails generate scaffold setting <attr_name1>:<type1> ..., you are able to create the following:
A migration for the database that creates the settings table.
Generation of the model object Setting that maps to the created database table.
A controller SettingsController that allows CRUD for your model objects.
View files for the actions generated for the controller.
You can all do that by hand, but it is a good starting point to begin with. And read the basic tutorials and play with the example applications to get a feeling for Rails ...
I am creating a simple RoR application where I can create posts and also comment on them. My thought on how to do this is to have posts and comments be of the same type and utilizing the same MVC except comments have a parent id. Posts will have a parent id of 0 while comments will have the id of its parents. I was thinking of when I tried to create a comment, I could just pass in the parent's id to the new method. This did not work. Although I got no errors it seems like the #post variable in the new method is not the same #post variable in the create method. My intuition was that the new method creates a new object then passes the object to the view. The view then populates the objects parameters and then sends it to the create method and the create method saves the object to the database. From trial and error this does not seem to be the case unless I am just doing it wrong. Is there an easier way to get the same functionality I am trying to achieve? or is there a way to get my way to work? any help would be greatly appreciated!
I would recommend you follow the classic "Build a Blog in 15 minutes" video that shows you how to do this.
Among other things, since a post has_many :comments I wouldn't recommend doing what you're proposing.
when we have validate_presence_of :name in the model and then when we put in the create action that we re-render 'new', then the form_for will populate the fields, and error_messages_for 'story' will have the correct error message.
this is really great, and and the same time, this looks like magic... i found that many books don't explain how the magic occur. is it by some global variable?
when the form_for is called... is it using the #story that came back from the #story.save, instead of the #story = Story.new from the new action? so if i use :story for the form_for, the fields won't be populated on error?
sometimes i feel that i am playing magic when using Ruby on Rails, except I don't know how the magic happens... kind of like if I make the rabbit appear, but I don't know how I did it. So I really want to know the inner workings of Rails.
Yes, Rails is very magical. Unfortunately these are just things that you have to learn to live with, and once you get used to the conventions you get to use the magic to do some very complicated things with great ease.
There are three separate issues here that are relatively simple individually but look very magical when you take it all in at once. Let's break them down one by one:
When validations fail, they disallow the model object from being saved and add errors to the object.errors hash.
When you run #story.save, it kicks off all the validations. Since #story.name is blank, validates_presence_of :name adds an error to the object.
Instance variables in the controller are available to the views they render.
So, yes, it is the same #story that the view has access to - the one that is invalid and has error information attached to it.
form_for takes many forms, and the one you're using is very smart
The form_for tag in your view probably looks like this:
<%= form_for #story do |story| =>
This is a special version of form_for that infers all kinds of information from the object passed in and renders the form appropriately. #story has some of its fields populated because of the line
#story = params[:story]
in your controller, so it goes ahead and fills in those fields for you. It does some other things, too - for example, it checks #story.new_record? to see if it should use the POST HTTP method (RESTful create) or the PUT method (RESTful update).
In summary, there are lots of little bits of magic to learn, but once you do the big magic is much easier to understand. Good luck!